Высокое использование центрального процессора при борьбе с futex - программирование
Подтвердить что ты не робот

Высокое использование центрального процессора при борьбе с futex

Я заметил, что когда futexes linux утверждаются, система тратит A LOT времени в спин-блоки. Я заметил, что это проблема, даже когда futexes не используются напрямую, но также при вызове malloc/free, rand, glib-мьютекс-вызовы и других вызовов системных/библиотечных, которые вызывают вызовы futex. Есть ли способ избавиться от этого поведения?

Я использую CentOS 6.3 с ядром 2.6.32-279.9.1.el6.x86_64. Я также пробовал самое последнее стабильное ядро ​​3.6.6, загруженное непосредственно с kernel.org.

Первоначально проблема возникла на 24-ядерном сервере с ОЗУ 16 ГБ. Процесс имеет 700 потоков. Данные, собранные с помощью "персидской записи", показывают, что спин-блокировка вызывается из futex, вызванного из __lll_lock_wait_private и __lll_unlock_wake_private, и убирает 50% процессорного времени. Когда я остановил процесс с помощью gdb, обратные трассы показали, что вызовы __lll_lock_wait_private __lll_unlock_wake_private сделаны из malloc и бесплатны.

Я пытался уменьшить проблему, поэтому я написал простую программу, которая действительно показывает фьютекс, вызывающий проблему спин-блокировки.

Начните 8 потоков, каждый поток выполнит следующее:

   //...
   static GMutex *lMethodMutex = g_mutex_new ();
   while (true)
   {
      static guint64 i = 0;
      g_mutex_lock (lMethodMutex);
      // Perform any operation in the user space that needs to be protected.
      // The operation itself is not important.  It the taking and releasing
      // of the mutex that matters.
      ++i;
      g_mutex_unlock (lMethodMutex);
   }
   //...

Я запускаю это на 8-ядерном компьютере с большим количеством ОЗУ.

Используя "верх", я заметил, что машина 10% в режиме ожидания, 10% в пользовательском режиме и 90% в системном режиме.

Используя "perf top", я заметил следующее:

 50.73%  [kernel]                [k] _spin_lock
 11.13%  [kernel]                [k] hpet_msi_next_event
  2.98%  libpthread-2.12.so      [.] pthread_mutex_lock
  2.90%  libpthread-2.12.so      [.] pthread_mutex_unlock
  1.94%  libpthread-2.12.so      [.] __lll_lock_wait
  1.59%  [kernel]                [k] futex_wake
  1.43%  [kernel]                [k] __audit_syscall_exit
  1.38%  [kernel]                [k] copy_user_generic_string
  1.35%  [kernel]                [k] system_call
  1.07%  [kernel]                [k] schedule
  0.99%  [kernel]                [k] hash_futex

Я ожидаю, что этот код потратит некоторое время на спин-блокировку, поскольку код futex должен получить очередь ожидания futex. Я также ожидал, что код потратит некоторое время в системе, поскольку в этом фрагменте кода в пользовательском пространстве работает очень мало кода. Однако 50% времени, затрачиваемого на спин-блокировку, кажется чрезмерным, особенно когда это время процессора требуется для выполнения другой полезной работы.

4b9b3361

Ответ 1

Я столкнулся с подобными проблемами. Мой опыт в том, что вы можете увидеть удар производительности или даже взаимоблокировки при многократном блокировании и разблокировке, в зависимости от версии libc и многих других неясных вещей (например, звонки в fork(), такие как здесь).

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

Для меня я видел воспроизводимый тупик, когда у меня было несколько потоков, занимающихся блокировкой и разблокировкой. Я использовал rootfs Debian 5.0 (встроенную систему) с libc с 2010 года, и проблема была устранена путем обновления до Debian 6.0.