SSE. Распараллеливание?

Тема в разделе "WASM.BEGINNERS", создана пользователем PUSH, 29 дек 2008.

  1. PUSH

    PUSH New Member

    Публикаций:
    0
    Регистрация:
    4 авг 2008
    Сообщения:
    25
    Вчера покурил термин SSE и описание сего Intel-овского бЛАГА. Правильно ли я понял, что он(о?) позволяет распараллелить работу с регистрами? (хрень какая-то... :dntknw: ).
    В Вики сказано, что "Преимущество в производительности достигается в том случае, когда необходимо произвести одну и ту же последовательность действий над разными данными.

    Реализация блоков SIMD осуществляется распараллеливанием вычислительного процесса между данными. То есть когда через один блок проходит поочерёдно множество потоков данных.".

    Код (Text):
    1. float a[4] = { 300.0, 4.0, 4.0, 12.0 };
    2. float b[4] = {   1.5, 2.5, 3.5,  4.5 };
    3.  
    4. _asm {
    5. movups xmm0, a   ; // поместить 4 переменные с плавающей точкой из a в регистр xmm0
    6. movups xmm1, b   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm1
    7.  
    8. mulps xmm1, xmm0 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    9.                  ; // xmm10 = xmm10*xmm00
    10.                  ; // xmm11 = xmm11*xmm01
    11.                  ; // xmm12 = xmm12*xmm02
    12.                  ; // xmm13 = xmm13*xmm03
    13.  
    14. movups a, xmm1   ; // выгрузить результаты из регистра xmm1 по адресам a
    15. };
    То есть, сделав:

    Код (Text):
    1. float a[8][4] = { 300.0, 4.0, 4.0, 12.0 };
    2.  
    3. _asm {
    4. movups xmm0, a[0]   ; // поместить 4 переменные с плавающей точкой из a в регистр xmm0
    5. movups xmm1, a[1]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm1
    6.  
    7. movups xmm2, a[2]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm2
    8. movups xmm3, a[3]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm3
    9. movups xmm4, a[4]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm4
    10. movups xmm5, a[5]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm5
    11. movups xmm6, a[6]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm6
    12. movups xmm7 a[7]   ; // поместить 4 переменные с плавающей точкой из b в регистр xmm7
    13.  
    14. mulps xmm1, xmm0 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    15.                  ; // xmm10 = xmm10*xmm00
    16.                  ; // xmm11 = xmm11*xmm01
    17.                  ; // xmm12 = xmm12*xmm02
    18.                  ; // xmm13 = xmm13*xmm03
    19. mulps xmm3, xmm2 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    20. mulps xmm5, xmm4 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    21. mulps xmm7, xmm6 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    22.  
    23. movups a[0], xmm1   ; // выгрузить результаты из регистра xmm1 по адресам a
    24. movups a[2], xmm3   ; // ит.д.
    25. movups a[4], xmm5   ; // ит.д.
    26. movups a[6], xmm7   ; // ит.д.
    27. };
    Эт чЁ? всмысле мы можем, мало того, что "прогоняем 4 вещественных за один проход", еще и получить значения наших 4 "проходов" за один "проход"?
    Просветление не приходит... :dntknw:
    P.S. Извините за "не ассемблерную" реализацию части программы :)
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    PUSH
    Несовсем.
    1. В регистр мы можем поместить 128бит. Допустим у нас переменные float его размер 4байта. Тоесть в один регистр мы можем загрузить 4 числа.

    2. Записа в таком виде
    Код (Text):
    1. mulps xmm1, xmm0 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    2. mulps xmm3, xmm2 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    3. mulps xmm5, xmm4 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    4. mulps xmm7, xmm6 ; // перемножить пакеты плавающих точек: xmm1=xmm1*xmm0
    Мы тоже получим прирос. Потому что процессор имеет несколько ALU (4-5 штук). На старых процессорах можно было выполнять SSE команды только на 2 ALU. В современных на 4.
    То есть и тут мы иммем прирост в 2-4раза.

    Итог 8-16раз прирост скорости.
     
  3. PUSH

    PUSH New Member

    Публикаций:
    0
    Регистрация:
    4 авг 2008
    Сообщения:
    25
    То есть, все-таки, в данном случае РЕЗУЛЬТАТ в xmm3, к примеру, УЖЕ НАЧНЕТ ВЫЧИСЛЯТЬСЯ, когда ЕЩЕ НЕ ЗАКОНЧИТСЯ вычисление для xmm1?
    Именно этот момент, я, по сути дела никак не могу вкурить :dntknw:
     
  4. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    PUSH
    Если команды не зависимы. Тоесть как у нас. То они могут выполняться паралельно. Это зависит от многих параметров были ли ALU свободны или нет. Спаренные команды или нет.
    Если преположить идеальные условия. То 4 команды начнут выполняться одновременно. В неидеальных условиях. У нас может быть так, что какие-то могут начаться раньше. Но так как у нас дальше есть еще команды, то они будут выполняться как только ALU освободиться. Но на паралельно алу тоже освободиться команда и там тоже будет на замену. Так что это отстование не будет увеличиваться уменьшаться и все будет тоже паралельно.
    Это как соревнования в басеене. 8 дорожек все плывут паролельно кто-то впереди кто-то позади но все плывут паролельно. Первый проплыл. Второй человек из команды прыгает в бассен. На свою дорожку. Да он в переди. Но на паралельной дорожке тоже приплыл и у него из команды тоже второй номер прыгает в бассеен. Только в бассене 8 дорожек. А у нас 4 ALU 5 труб/каналов(англ pipes).
     
  5. PUSH

    PUSH New Member

    Публикаций:
    0
    Регистрация:
    4 авг 2008
    Сообщения:
    25
    Вуааа!!! ПРОСВЕТЛЕНИЕ!!!
    Теперь, другая догадка. А на [censored - подставлять слово по мере извращенности воображения] тогда сейчас ввели идею с двух (трех, четырех... - подставлять слово по мере извращенности воображения) яДР(Ё)(Я)НЫХ процессоров. Не легче ли бы просто налепить на бедный кусочек кремния побольше АЛУ? Я как просветлился - дело в сложности охлаждения. Но ведь вся эта белиберда (в случае с многоЯДР(Ё)(Я)НЫМИ моделями) и так находится на ОДНОМ КУСОЧКЕ КРЕМНИЯ. Начерта было разделять на "группы алу"? Они ведь, вроде, пользуются единым кешем и т.д. Или там на каждое ядро по своему комплекту FPU и проч. радостей?
    P.S. Наумничал, однако... :)
     
  6. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    В видео карте так и сделали 128 и более(Правда там считается что ALU работает с одним числом типа float или double).

    Там кэш только общий. Бывает разделенный. Все остальное раздельно. И у каждого ядра свой комплект ALU и прочей радости. Есть эксперементы про задействования ALU других ядер.
    ALU можно нолипить, но он бы простаивал по большему времени, пока процессор не дойдет до исполнения следующего трудоемкого блока. А многоядерность позволяет сократить такии промяжутки.
     
  7. PUSH

    PUSH New Member

    Публикаций:
    0
    Регистрация:
    4 авг 2008
    Сообщения:
    25
    То есть исполняемый файл в многоядерном иполнении, мало того, что исполняется, но и преданализируется (если можно так сказать) процессором одновременно?
    То есть, поступил "заказ" на исполнение. Одно ядро надевает акваланг и погружается в трясину алгоритма, а остальные пробегают код (забугорными словами типа "парсинг" кидаться язык не поворачирается), анализируя, что в нем можно было бы еще бы такое попросчитывать, чтобы первый погрузившийся поменьше парился. Или теперь в сами исполняемые файлы должны содержать таблицы, указывающие "предпросчетные" участки кода.
    Или вообще многоядерность будет активируется лишь в том случае, когда программист выделит какое-либо определенное вычисление в нить (thread - прости меня,русский язык :) ) процесса.
     
  8. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Многоядерность позволяет выполнять потоки одновременно. В случае двух ядер это будут два одновременно выполняемых потока, в случае четырёх - четыре и т.д. Сам же поток не может размазаться между двумя ядрами.
     
  9. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Может и 2 одновременных потока на ядро быть.
     
  10. t00x

    t00x New Member

    Публикаций:
    0
    Регистрация:
    15 фев 2007
    Сообщения:
    1.921
    PUSH
    потоками и процессами распоряжается операционная система, она выделяет промежутки времени для выполнения. необязательно один и тот же поток будет выполнятся на одном и том же ядре.
    вытесняющая многозадачность способна попортить преимущества аппаратного ускорения :)
     
  11. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    В случае HyperThreading - да. В данном случае ядро одно, а логических процессоров два.
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Pavia
    Ну ты и загнул. Это что ж за суперпроцессоры такие "современные" ? В атлонах и Core 2 только по 3 порта запуска SSE и к тому же не универсальных, в частности умножитель у всех только один, поэтому mulps могут распараллелиться со сложениями\мувами и т.п., а цепочка одних mulps - никак
     
  13. PUSH

    PUSH New Member

    Публикаций:
    0
    Регистрация:
    4 авг 2008
    Сообщения:
    25
    Мда... Я понял ошибку всей моей жизни - надо было не PUSH-ем называться, а БЛОНДИНК-ой... :) ... А еще программистом себя считал. :dntknw:
    Основательно покурив это небольшое обсуждение я все-таки просветлился насчет многоЯДРЕННОСТИ. (А то, бедняга, ночами не спал - мучался вопросом "НАХРЕНА?"). Получается, что просто "порции" виртуальных страниц разжевываются несколькими ядрами сразу. Остался только один, наверное такой же глупый, как и предыдущие вопрос - надо ли уяснять как-нибудь в программе (новые оппкоды или специальные указания транслятору), что мы пишем с возможностью многоядерности, или даже написанные для одноядерных машин программы, многодерные пережуют, ускорив их выполнение распараллеливанием (а может все-таки не блондинка? :) ).
    И насчет SSE... Получается ускорение мы получаем только засчет вычисления пакетных (байтов, слов - все что душе угодно, в пределах 128 разрядов) за "один проход"? По сути дела для ЭТОГО я и начал череду этих глупых вопросов...
    P.S. Благодарю за "информацию к просветлению"... Она очень хорошо курится :)
     
  14. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    leo
    Мне казалось что там 4. А оказалось 3. Тогда я спокоен в следующем поколении сделают. А то я уж было решил что интел все свои козыри раскрыла.

    PUSH
    Программы написанные для одноядерников и многоядерников можно запускать на обоих машинах.
    Другое дело что программа рассчитанная на одноядерник используют один поток то прироста не будет.
    Если они рассчитаны на несколько потоков, то может оказать в результате ошибке на одноядерной машине они будут работать корректно, а на многоядерной нет. Если ошибок нет то будет прирост производительности.

    Отдельно, нужно сказать, что программа на писанная под однопроцессорник и один поток должна работать корректно на многоядернике. Но все-таки может работать не корректно. Во время переключения поток может быть запущен на другом ядре. Казалось бы, ничего страшного, но счетчик татов (RDSTC) на разных ядрах разный и в результате расхождения получалось отрицательное время!!! Вроде как ИТ индустрия справилась с этим.
    Если ты хочешь использовать многоядерность, то для этого есть много путей. К примеру в VS можно указать ключь OpenMP, он подключает соответствующие библиотеки/модули производит настройку и ты сможешь пользоваться OpenMP. Это библиотека макросов, которая позволяет управлять параллельностью. То, есть как управлять. Ты настраиваешь синхронизацию. Можешь указать какой участок нужно распараллелить какой должен обрабатывать первый. Где второй процесс должно подождать первый.
    Вроде где-то слышал есть очень умные компиляторы, которые сами могут распараллелить код.

    Это можно сделать и без OpenMP в виндоусе для этих целей есть набор средств/функций.

    Что касается низкоуровневых механизмов. То для синхронизации есть префикс LOCK и им обязательно надо пользоваться, и пользоваться аккуратно.
     
  15. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    ну есть по дефолту команды, работающие с #LOCK: это, например, xchg, основа мьютексов :).