Подтвердить что ты не робот

Проблема блокировки приложений Python/OpenCV

Приложение My Python, работающее на 64-ядерном Linux-сервере, обычно работает без проблем. Затем, после некоторого случайного промежутка времени (обычно от 0,5 до 1,5 дней), я внезапно начинаю частые паузы/блокировки более 10 секунд! Во время этих блокировок системное время процессора (т.е. Время в ядре) может быть более 90% (да: 90% всех 64 ядер, а не только одного процессора).

Мое приложение перезапускается часто в течение дня. Перезапуск приложения не устраняет проблему. Однако перезагрузка машины.

Вопрос 1. Что может привести к 90% времени системного процессора в течение 10 секунд? Все системное время процессора находится в моем родительском процессе Python, а не в дочерних процессах, созданных с помощью многопроцессорности Python или других процессов. Таким образом, это означает что-то порядка 60+ потоков, затрачивающих 10+ секунд в ядре. Я даже не уверен, что это проблема Python или проблема ядра Linux.

Вопрос 2: проблема с перезагрузкой проблемы должна быть большой подсказкой в ​​отношении причины. Какие ресурсы Linux могут быть исчерпаны в системе между перезагрузкой приложения, но не между перезагрузками, которые могут заставить эту проблему застревать?

То, что я пробовал до сих пор, чтобы решить эту проблему/выяснить ее

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

  • Мое приложение запускает поток, который использует psutil для вывода статистики процесса и системного процессора каждые 0,5 секунды. Я самостоятельно подтвердил, что он сообщает с помощью top.
  • Я конвертировал мое приложение из Python 2.7 в Python 3.4, потому что Python 3.2 получил новую реализацию GIL, а 3.4 перезаписал многопроцессорную обработку. Хотя это улучшило ситуацию, оно не решило проблему (см. мой предыдущий вопрос SO, который я ухожу, потому что это еще полезный ответ, если не общий ответ).
  • Я заменил ОС. Первоначально это был Ubuntu 12 LTS, теперь это CentOS 7. Никакой разницы.
  • Получается многопоточное и многопроцессорное столкновение в Python/Linux и не рекомендуется вместе, у Python 3.4 теперь есть forkserver и spawn контексты многопроцессорности. Я пробовал их, никакой разницы.
  • Я проверил /dev/shm, чтобы убедиться, что у меня закончилась общая память (которую использует Python 3.4 для управления многопроцессорной обработкой), ничего
  • lsof вывод списка всех ресурсов здесь
  • Трудно проверить на других машинах, потому что я запускаю многопроцессорный пул из 59 детей, и у меня нет других 64-х основных машин, которые просто лежат
  • Я не могу запускать его с помощью потоков, а не процессов, потому что он просто не может работать достаточно быстро из-за GIL (следовательно, почему я переключился на многопроцессорность в первую очередь).
  • Я попытался использовать strace только в одном потоке, который работает медленно (он не может работать во всех потоках, потому что он слишком сильно замедляет приложение). Ниже я получил то, что не говорит мне много.
  • ltrace не работает, потому что вы не можете использовать -p для идентификатора потока. Даже просто запустить его в основном потоке (нет -f) делает приложение настолько медленным, что проблема не появляется.
  • Проблема не связана с загрузкой. Иногда он будет работать нормально при полной нагрузке, а затем при половинной нагрузке он вдруг столкнется с этой проблемой.
  • Даже если я перезагружаю компьютер каждую ночь, проблема возвращается каждые пару дней.

Среда/примечания:

  • Python 3.4.3, скомпилированный из источника
  • CentOS 7 полностью обновлен. uname -a: Linux 3.10.0-229.4.2.el7.x86_64 # 1 SMP Wed 13 мая 10:06:09 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux (хотя это обновление ядра было применено только сегодня)
  • Машина имеет 128 ГБ памяти и имеет множество бесплатных
  • Я использую numpy, связанный с ATLAS. Я знаю, что OpenBLAS сталкивается с многопроцессорностью Python, но ATLAS этого не делает, и это столкновение решается с помощью Python 3.4 forkserver и spawn, которые я пробовал.
  • Я использую OpenCV, который также выполняет много параллельной работы.
  • Я использую ctypes для доступа к библиотеке C.so, предоставленной производителем камеры.
  • Приложение работает под управлением root (требование библиотеки C, на которую я ссылаюсь)
  • Многопроцессорность Python Pool создается в коде, защищенном if __name__ == "__main__": и в основном потоке

Обновлены результаты strace

Несколько раз мне удалось привязать поток, который работал на 100% "системном" процессоре. Но только однажды я получил от него что-то значимое. См. Ниже вызов в 10: 24: 12.446614, который занимает 1,4 секунды. Учитывая тот же идентификатор (0x7f05e4d1072c), который вы видите в большинстве других вызовов, я предполагаю, что это синхронизация PILON GIL. Означает ли это предположение? Если это так, то возникает вопрос, почему ожидание занимает 1,4 секунды? Кто-то не выпускает GIL?

10:24:12.375456 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.000823>
10:24:12.377076 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.002419>
10:24:12.379588 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.001898>
10:24:12.382324 sched_yield()           = 0 <0.000186>
10:24:12.382596 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.004023>
10:24:12.387029 sched_yield()           = 0 <0.000175>
10:24:12.387279 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.054431>
10:24:12.442018 sched_yield()           = 0 <0.000050>
10:24:12.442157 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.003902>
10:24:12.446168 futex(0x7f05e4d1022c, FUTEX_WAKE, 1) = 1 <0.000052>
10:24:12.446316 futex(0x7f05e4d11cac, FUTEX_WAKE, 1) = 1 <0.000056>
10:24:12.446614 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <1.439739>
10:24:13.886513 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.002381>
10:24:13.889079 sched_yield()           = 0 <0.000016>
10:24:13.889135 sched_yield()           = 0 <0.000049>
10:24:13.889244 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.032761>
10:24:13.922147 sched_yield()           = 0 <0.000020>
10:24:13.922285 sched_yield()           = 0 <0.000104>
10:24:13.923628 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.002320>
10:24:13.926090 sched_yield()           = 0 <0.000018>
10:24:13.926244 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.000265>
10:24:13.926667 sched_yield()           = 0 <0.000027>
10:24:13.926775 sched_yield()           = 0 <0.000042>
10:24:13.926964 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.000117>
10:24:13.927241 futex(0x7f05e4d110ac, FUTEX_WAKE, 1) = 1 <0.000099>
10:24:13.927455 futex(0x7f05e4d11d2c, FUTEX_WAKE, 1) = 1 <0.000186>
10:24:13.931318 futex(0x7f05e4d1072c, FUTEX_WAIT, 2, NULL) = 0 <0.000678>
4b9b3361

Ответ 1

Мне удалось получить дамп потока из gdb прямо в точке, где 40 + потоки показывают 100% -ное время процессора.

Здесь обратная трассировка, которая одинакова для каждого из этих потоков:

#0  0x00007fffebe9b407 in cv::ThresholdRunner::operator()(cv::Range const&) const () from /usr/local/lib/libopencv_imgproc.so.3.0
#1  0x00007fffecfe44a0 in tbb::interface6::internal::start_for<tbb::blocked_range<int>, (anonymous namespace)::ProxyLoopBody, tbb::auto_partitioner const>::execute() () from /usr/local/lib/libopencv_core.so.3.0
#2  0x00007fffe967496a in tbb::internal::custom_scheduler<tbb::internal::IntelSchedulerTraits>::local_wait_for_all(tbb::task&, tbb::task*) () from /lib64/libtbb.so.2
#3  0x00007fffe96705a6 in tbb::internal::arena::process(tbb::internal::generic_scheduler&) () from /lib64/libtbb.so.2
#4  0x00007fffe966fc6b in tbb::internal::market::process(rml::job&) () from /lib64/libtbb.so.2
#5  0x00007fffe966d65f in tbb::internal::rml::private_worker::run() () from /lib64/libtbb.so.2
#6  0x00007fffe966d859 in tbb::internal::rml::private_worker::thread_routine(void*) () from /lib64/libtbb.so.2
#7  0x00007ffff76e9df5 in start_thread () from /lib64/libpthread.so.0
#8  0x00007ffff6d0e1ad in clone () from /lib64/libc.so.6

Мой оригинальный вопрос поставил Python и Linux на передний и центральный, но проблема, похоже, связана с TBB и/или OpenCV. Поскольку OpenCV с TBB настолько широко используется, я полагаю, что он должен также каким-то образом задействовать взаимодействие с моей конкретной средой. Может быть, потому что это 64-ядерная машина?

Я перекомпилировал OpenCV с отключенным TBB, и проблема пока не появилась. Но теперь мое приложение работает медленнее.

Я разместил это как ошибку для OpenCV и обновит этот ответ всем, что от этого получится.