LINUX.ORG.RU

SMP и потоки


0

0

Столкнулся с проблемой.
вот код
struct work_t
{
  std::deque<int> data;
  boost::mutex * mutex;
};

std::vector<work_t> work_data;
void worker (const int & n)
{
  std::ofstream ostr(...);
  while(!stop)
    {
      int s = 0;
      {
      boost::mutex::scoped_lock lk(*(work_data[n].mutex));
      if(!work_data[n].data.empty())
	{
	  s = work_data[n].data.front();
	  work_data[n].data.pop_front();
	}
      }
      if(s != 0)
	{
	  do_some_work(s);
	}
      if(have_results)
        {
           write_results(ostr);
        }
    }
}


int main()
{
  //...
  // Заполнение и инициализация массива work_data
  //..
  boost::thread_group grp;
  for(int i=0;i<nthread;++i)
    {
      grp.create_thread(boost::bind(&worker,i));
    }
  grp.join_all();
  //...
}
Каждый поток работает со своей порцией данных.
mutex защищающий данные  потока, на данный момент, всегда свободен. Т.е. поток никогда не должен в нем засыпать.
Если я запускаю 4 потока на машине с AMD Athlon64  3000, то в htop 
видно что все потоки находятся в состоянии R и отбирают 100% 
процессорного времени, которое делится между потоками. Вроде все 
нормально. 

Но если эти же 4 потока, на тех же самых данных запустить на 4-х 
процессорной машине с DualCore Opteron 875, то загрузка на всех 
процесорах не превышает 50% и одновременно работает только 1 или 2 
потока остальные висят в состоянии D (насколько я понял это означает 
что поток заблокирован).

Кто-нибудь может мне объяснить с чем связано такое поведение?
Хочется все-таки загрузить машину по полной.
★★

Вероятно, что-то осталось за скобками: есть еще какая-то синхронизация в do_some_work или write_results.

anonymous
()
Ответ на: комментарий от e

Да ну брось ...

И потом ничего особенно плюс-плюсного не было редемонстрировано - разве что Mutex удобно и надежно освобождается при выходе из блока.

anonymous
()
Ответ на: комментарий от e

А что конкретно в man gcc искать?

Есть подозрение, что такое поведение вызвано тем что архитектура машины не SMP а NUMA.

Vinick ★★
() автор топика
Ответ на: комментарий от anonymous

>>Вероятно, что-то осталось за скобками: есть еще какая-то синхронизация в do_some_work или write_results.

У меня ее точно нет, только если где-то внутри стандартных библиотек.

Vinick ★★
() автор топика
Ответ на: комментарий от anonymous

>>четырехпорцессорная NUMA ??
Ага,
$numactl --hardware
available: 4 nodes (0-3)
node 0 size: 2015 MB
node 0 free: 152 MB
node 1 size: 1507 MB
node 1 free: 67 MB
node 2 size: 2020 MB
node 2 free: 66 MB
node 3 size: 2020 MB
node 3 free: 72 MB
node distances:
node   0   1   2   3
  0:  10  20  20  20
  1:  20  10  20  20
  2:  20  20  10  20
  3:  20  20  20  10

Vinick ★★
() автор топика
Ответ на: комментарий от Vinick

> Есть подозрение, что такое поведение вызвано тем что архитектура машины не SMP а NUMA.

1. С точки зрения операционки разницы между ссNUMA и чистым SMP нету, за исключением различной memory affinity, что явно не при чем.

2. Практически все современные интелоподобные архитектуры толще 2 процессоров -- NUMA.

3. Состояние D означает Uninterruptible sleep в ядре, обычно это -- ожидание ввода/вывода. На однопроцессорной архитектуре такое обычно незаметно: поскольку I/O ресурсы процессорами не делятся, ждать нечего.

Вывод: do_some_work(s) или write_results(ostr) копай. Думаю, последнее.

Die-Hard ★★★★★
()
Ответ на: комментарий от Die-Hard

Все перекопал, но так ничего интересного и не нашел. Единственно через 
strace заметил что постоянно идет вызов пары mmap/munmap на 160 кб по 
одному и тому же адрессу.
В итоге отказался от многонитевой архитектуры в пользу 
многопроцессорной. Теперь все нормально работает, загрузка процессоров 
на 97-100%, производтельность приемлемая, задача сдана :)


>>1. С точки зрения операционки разницы между ссNUMA и чистым SMP 
нету, за исключением различной memory affinity, что явно не при чем.
                                                    ^^^^^^^^^^^^^^^         

Откуда такой вывод? Можете объяснить? В принципе внутри do_some_works происходит 
обращение на чтение к глобальным массивам на 150-200 Мб созданым 
родительским потоком (эти массивы заполнены до старта рабочих потоков 
и в процессе не изменяются, поэтому я их блокировками не защищал) да и
 внутри потока происходит выделение и копирование примерно таких же 
объемов. Я думал, что как раз разная скорость доступа к памяти в этом 
случае и может выстрелить.  Хотя я пробовал запускать многопоточную 
версию на 2-x процессорном Pentium Xeon c HT,которые вроде чистый SMP,
 там наблюдается точно такое же поведение, но не сразу - какое-то 
время потоки работают на все 100% а потом начинают "деградировать", 
т.е. впадать в uninterruptible sleep.

Vinick ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.