Реализация многопоточной суперлинейной производительности с учетом режима усиления CPU

0

Я изучаю класс в С++ 11, используя MinGW 4.8.1 lib на WIN7 64-разрядной ОС.

Процессор ARK | Процессор Intel Core i7-820QM, который имеет четыре физических ядра с кешем 8M и поддерживает максимум восемь потоков. Этот процессор имеет базовую частоту работы 1,73 ГГц, если четыре ядра используются одновременно и могут быть увеличены до 3.08 ГГц, если используется только одно ядро.

Основной целью моего изучения является то, что я собираюсь внедрить многопоточную тестовую программу, чтобы продемонстрировать, что увеличение линейности увеличивается по мере увеличения количества потоков.

Здесь SUPER-линейный термин означает ровно 4 раза ускорения (возможно, в 3,8 раза) при использовании четырех потоков по сравнению с одной нитью, а не 3,2 или 3,5 раза.

Коды и результаты вставляются здесь,

inline void count(int workNum)  // some working to do . 
                                //These codes are extracted from a real application except that the count function do some "meaningful" job and 
                                //these codes have identical speedup ratio as my real application.
{
     int s=0;  
     for(int i=0;i<workNum;++i)
       ++s;    
}

inline void devide(int numThread)  // create multiThreads [1,7] to do same amount task 
{
    int max = 100000000;
    typedef std::vector<std::thread>  threadList;
    threadList list;
    for(int i=1;i<=numThread;++i){
       list.push_back(std::thread(count,max/numThread));    
    } 
    std::for_each(list.begin(),list.end(),std::mem_fun_ref(&std::thread::join));   
}

inline void thread_efficiency_load()  // to start test 
{       
   for(int i=7;i>0;--i)
   {
     std::cout<< "*****************************************" << std::endl; 
     std::chrono::time_point<std::chrono::system_clock> start, end;
     start = std::chrono::system_clock::now();

     devide(i); // this is the work load to be measured, which i is the number of thread  

     end = std::chrono::system_clock::now();
     std::chrono::duration<double> elapsed_seconds = end-start;
     std::cout << "thread num=#" << i << "  time=" <<  elapsed_seconds.count() << std::endl;      
   }   
}   

Выход:

 The time unit is seconds,

 *****************************************
 thread num=#7  time=0.101006
 *****************************************
 thread num=#6  time=0.0950055
 *****************************************
 thread num=#5  time=0.0910052
 *****************************************
 thread num=#4  time=0.0910052
 *****************************************
 thread num=#3  time=0.102006
 *****************************************
 thread num=#2  time=0.127007
 *****************************************
 thread num=#1  time=0.229013

Это очень ясно, что я не получаю сверхлинейную производительность при увеличении числа потоков. Я хотел бы знать, почему я этого не понимаю. Зачем? Зачем? Зачем?

Некоторые основные вещи из моего разума,

Из-за того, что есть только 4 физических ядра, поэтому максимальное ускорение должно появиться, когда есть четыре активных потока (больше потоков не очень помогает). В 4 раза быстрее, чем в сингле, в 2,4 раза быстрее, чем ожидается в 4 раза. Я надеюсь, что вышеупомянутая реализация блокирует 4-кратное ускорение из-за проблемы с памятью (кэширование страниц), потому что все переменные являются локальными переменными.

Рассматривая режим повышения процессора, процессор увеличивает рабочую частоту до 3,07 ГГц, когда есть только одно занятое ядро, где отношение составляет 1,7 (базовая рабочая частота ядер 1,79 ГГц), 2,4 * 1,7 составляет около 4, как исключено, это действительно означает, что ускорение в 2,4 раза - это максимальное ускорение, которое может быть достигнуто по сравнению с режимом однопоточности с одновременным увеличением.

Я буду очень признателен, что вы можете ответить,

1) В приведенной выше реализации есть некоторые переменные, расположенные в одной и той же строке кеша, что приводит к большому количеству поискового вызова между многопоточными файлами для снижения производительности?
2) Как изменить приведенные выше коды для достижения сверхлинейной производительности (в 4 раза быстрее по сравнению с одной нитью) по мере увеличения числа потоков?

Большое спасибо за Вашу помощь.

  • 1
    Может быть, я что-то упустил, но почему есть шанс получить СУПЕР-линейное (больше, чем линейное) увеличение производительности, когда - даже в оптимальном случае - число параллельных доступных инструкций растет максимально линейно с количеством потоков и время, которое занимает одна операция, увеличивается из-за более низкой тактовой частоты.
  • 0
    @MikeMB, вы абсолютно правы. СУПЕР-линейный означает ровно 4 раза (может быть, 3,9 раза приемлемо), а не 3,2 или 3,5 раза. Это не может быть более 4 раз. Я также добавляю это в пост.
Показать ещё 4 комментария
Теги:
multithreading
c++11
boost

1 ответ

0

Точно так же, как предупреждение: аргументы в пользу фактических номеров производительности многопоточной программы на современной x86/x64-системе без RTOS всегда много догадок - слишком много уровней между вашим кодом c/c++ и фактическим операции, выполняемые на процессоре.

Как грубая оценка верхней границы, да, для рабочей нагрузки ALU (не памяти) -bound вы не получите намного больше, чем 1,73 * 4/3.08 = 2,24 раза коэффициент ускорения для 4 потоков на 4 ядра против 1 потока на одном ядро даже в идеальном случае. Помимо этого, я утверждаю, что ваши тесты "рабочая нагрузка" слишком малы, чтобы получить значимые результаты теста. Как уже упоминалось в комментариях, компилятору будет разрешено полностью заменить вашу рабочую нагрузку на операцию NOP, оставив вам только накладные расходы на создание и объединение потоков и ваших измерений (хотя я не думаю, что это произошло здесь).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню