OpenCL: универсальность и высокая производительность или не так все просто?

На Хабре уже были статьи об OpenCL, CUDA и GPGPU со сравнениями производительности, базовыми понятиями и примерами, поэтому рассказывать об основах и принципах работы я тут не буду, даже код не покажу. Но я хочу описать в чем заключаются реальные трудности при использовании GPU (про ограничения и их последствия), почему нельзя сравнивать производительность CPU и GPU, а также про то насколько “универсален” OpenCL на самом деле.

Предисловие


Мое знакомство с GPGPU началось 1,5 года назад и продолжается до сих пор в виде активной разработки исследовательского проекта. Тогда у меня был выбор: OpenCL или CUDA, разницы в выборе особо, на тот момент, не было, но в университете начали читать курс про OpenCL, так я его и выбрал. Сразу скажу, что писал я только для карт с архитектурой от NVidia, поэтому буду говорить про нее (чаще всего о Fermi).

В этом месте был большой абзац об истории и состоянии дел в области расчетов на GPU, но после описания проблем пост оказался слишком длинным и абзац был жестоко урезан (есть надежда, что он вернется в следующей части). Поэтому перейдем сразу к тому, почему портированные на GPU алгоритмы далеко не всегда работают быстро, т.е. дают на практике 0.5Х-10Х прироста производительности вместо обещанных 20Х-100Х относительно CPU (иначе бы уже каждое приложение его использовало).

Почем получается медленно?


Итак, все мы знаем, что архитектура GPU отличается от CPU весьма существенно, но мало кто задумывается над тем, насколько сильно это отличие и насколько сильно оно затрагивает разработку алгоритмов для GPU. Человек, хоть и является довольно параллельной системой, привык думать об алгоритмах последовательно. Последние ХХцать лет процессоры нам в этом потакали и мы все привыкли к тому, что одна команда выполняется после другой. А еще мы привыкли к тому, что ресурсы, доступные программе, практически не ограничены (не вспоминаем про микроконтроллеры), а данные можно получить почти сразу. На этом основаны почти все техники программирования и оптимизации. Только вот с GPU это не проходит и я хочу попробовать описать последствия наших привычек.

Ограничение первое: 32 потока (warp) всегда выполняют ОДНУ команду

Если где-то до этой команды было ветвление и потоки пошли по разным путям, то GPU будет выполнять обе ветки последовательно.
Таким образом попытка упростить расчеты для какого-то частного случая (если известно общее и короткое решение проблемы) может приводить не ускорению расчетов (что всегда происходит на CPU), а к сложению времени расчета общего и частного случая.
Другой пример: каждое ядро выбирает разный алгоритм в зависимости от типа данных, например надо рассчитать расстояние от точки до геометрической фигуры и каждое ядро получает разную фигуру и, соответственно, разный алгоритм. В итоге общее время будет суммой времени выполнения алгоритма для каждого объекта.
И оказывается, что мы считаем все точно также последовательно как и CPU (а при многих вложенных ветвлениях мы считаем на GPU гораздо больше, чем на CPU), только вот при последовательном расчете GPU будет в десятки раз медленнее. Обратите внимание сколько if-ов в Ваших программах, хотя если все 32 потока пойдут по одному пути, то все ок, но так ли это часто происходит во всех ветвлениях?

Ограничение второе: при каждом обращении к памяти всегда считываются 128 байт последовательно, даже если нам нужен только 1 байт

А еще один поток может получить доступ только к 16 байтам из этих 128 байт за один раз.
В результате получается, что пропускная способность памяти больше 150Гб/с, но только при условии, что все 128 байт используются постоянно. Если же каждый поток должен считать одну большую структуру, которая весит 40 байт, то каждый поток должен сделать 3 запроса к памяти и скачать 3*128 байт. А если данные для каждого потока располагаются в разных местах (а поток получает указатель на них и затем загружает, вполне нормальная ситуация для CPU, когда память расходуется рационально), то полезная пропускная способность памяти получается 40*32/(128*3*32), то есть порядка 10% от реальной.
И снова мы приблизились к показателям пропускной способности памяти доступной CPU. Можно конечно вспомнить про то, что есть кэш, но он появился только на Fermi и он не такой уж большой, хоть и помогает ощутимо. С другой стороны можно вспомнить, что на первых версиях GPU даже при последовательном считывании 128 байт в случае если они считываются не последовательно и/или смещены хотя бы на один байт, производится отдельный запрос к памяти для каждого потока.

Ограничение третье: латентность памяти составляет примерно 800 циклов для каждого запроса

А в прошлом примере для получения данных всеми процессами надо сделать 3*32 запроса… почти 80 тысяч циклов… Что делать в это время? Выполнять другие потоки и тут появляются новые ограничения.

Ограничение четвертое: на все активные потоки мультипроцессора выделяется 32к регистров

Сначала кажется, что много, но они выделяются на все активные потоки, а не только выполняющиеся (причем они выделяются статически по максимуму, сколько надо в самом худшем ветвлении, столько и будет выделено). А активных потоков должно быть 1536, чтобы скрывать латентность памяти (попробуйте посчитать легко ли скрыть 80 тысяч циклов из прошлого примера), то есть остается 21 регистр на поток. Попробуйте реализовать сложный алгоритм и уложиться в 21 регистр (это не только переменные, но и промежуточные результаты операций, счетчики циклов итд итп). С другой стороны, можно попробовать использовать меньше, чем полторы тысячи активных потоков и тут появляется следующее ограничение.

Ограничение пятое: планировщик потоков Fermi может запускать потоки только группами в 512 штук (до ферми было проще, в районе 128)

То есть доступно всего 3 опции: 1536 потоков если каждый использует меньше 21 регистра, 1024 потока если используется меньше 32 регистров или 512 потоков, меньше никак. При этом меньшее число потоков означает серьезные проблемы с попыткой скрыть латентность памяти и простоем целого мультипроцессора в течении тысяч циклов.
А это уже гораздо хуже, чем CPU. А самое плохое происходит если каждый поток использует больше 64 регистров.

Ограничение шестое: если поток использует больше 64 регистров, то они хранятся в глобальной памяти

Я до сих пор не могу поверить, что в глобальной памяти, а не в локальной, но так говорит документация. То есть появляются дополнительные запросы к памяти. Кстати, для вызова функций используется стек, который также занимает регистры (да да, функции — это плохо).

Для борьбы с использованием регистров и оптимизацией загрузки есть есть еще разделяемая память (shared которая, не помню как по-русски правильно). Но ее только 16/48Кб и она разделяется между всеми активными группами, то есть если каждая группа кушает 25кб памяти, то больше одной группы запустить не получится со всеми вытекающими последствиями.

Ограничение седьмое: запуск каждого ядра сопровождается небольшой задержкой

На самом деле тут все не так уж страшно, задержка эта измеряется десятками микросекунд. Но если Вы запускаете ядро 1000 раз, то это уже десятки миллисекунд, что в случае расчетов в реальном времени (рендеринга например) сразу создает ограничение в 15FPS даже без учета времени самих расчетов.

Тут должно было быть заключение, но будет в следующий раз

Только я разошелся, а уже получился слишком длинный список. А ведь еще надо вспомнить про синхронизацию, атомные операции, копирование данных на девайс, балансировку нагрузки для каждой карты (SLI тут не работает), точность, специальные функции, кривые драйвера, отладку и много чего еще. Да и про реальную универсальность OpenCL надо сказать многое. Ну да ладно, отложим это до следующих частей.

А, в целом, разработчики конечно знают (с приходом опыта после долгих мучений) о многих (но не всех) ограничениях и пытаются оптимизировать код так, чтобы их обойти, но представьте сколько времени уходит на то, чтобы переделать алгоритмы, которые разрабатывались без оглядки на GPU, да и не все алгоритмы можно переделать в принципе. Но я потихоньку “постигаю дзен” и понимаю, что не все так плохо и обещанные терафлопы получить таки можно, и об этом я также обещаю написать в следующих частях истории об OpenCL.
Поделиться публикацией

Похожие публикации

Комментарии 55

    –2
    Я конечно подозревал о сложностях работы с GPGPU но что все на столько плохо, для меня, конечно, неожиданность.
      +8
      Оно не то чтобы совсем плохо. Просто оно очень сильно отличается от CPU и, соответственно, надо привыкнуть к особенностям архитектуры GPU. То, что на CPU будет казаться жутко медленным и неоптимальным, на GPU может быть как раз лучшим решением, а мы к этому не привыкли. И наоборот.

      Я в следующем посте напишу про то как традиционная оптимизация GPU кода может вредить производительности. Слишком уж много раз я на этом попадался… сидишь оптимизируешь, вот видно прямо, что меньше операций должно выполняться, а получается медленнее.
      0
      Хмм, а подскажите, пожалуйста, есть ли какие-нибудь кулинарные книжки по разработке под GPU с нуля?
      «С нуля» означает, что не для новичка, а с нуля программы, когда она еще не испорчена обычными шаблонами, заточенными под CPU. Т.е. некий набор правил, которые следует пошагово держать в голове все время разработки.

      И еще: оцените, пожалуйста, адекватность использования (в т.ч. для запуск игрового веб-сервера, например) на базе супер-компьютеров Nvidia, при условии, что ПО будет написано именно с заточкой под GPU.
        +10
        Что касается книжек по GPGPU, то с ними все печально, есть пара популярных книжек от нвидии. Но, честно говоря, сильно много пользы они мне не принесли, там больше для совсем начинающих и про сам язык, простейшие вещи. Книжку о том, как надо думать чтобы все получилось я так и не нашел. Поэтому посоветовать ничего не могу кроме многократного перечитывания официальной документации по архитектуре на которой планируете все это запускать.

        На счет правил все интересно, тут на целую книгу наберется:)
        Из основного:
        — Забудьте сразу про то, что оно может запускаться на разных архитектурах. Если выбрали Fermi, то все под него.
        — GPU любит много ПРОСТЫХ потоков, если Вы не можете запустить 30к, до теоретического максимума не дойти.
        — Сразу думайте о том, как вы будете читать ваши данные и храните соответственно.
        — Латентность запуска ядра ~70микросекунд(не мс)
        — Иерархические структуры = либо медленно либо убьетесь поддерживать и придумывать как их распараллелить
        — На GPU много памяти, не надо ее экономить в ущерб производительности
        — На GPU ядра очень простые и мало регистров.
        — Главное — думайте заранее о том, как вы храните данные и, что вы с ними планируете делать. Все должно быть последовательно.
        — И еще лучше запустить простой алгоритм 3 раза, чем сложный 1 раз.

        Я попробую в следующем посте описать подробнее все это дело, сам сейчас думаю над архитектурой геометрической библиотеки под это дело… сильно и долго думаю, но тяжко это идет:)

        Игровой веб-сервер… не могу сказать конкретно, так как не представляю, что он должен считать. Если там будет считаться физика, то почему бы и нет, если просто много много расчетов каких-нибудь коэффициентов, то тоже хорошо, а дальше не скажу, у меня просто опыта разработки таких серверов. Все сильно зависит от задачи и от того, сколько вы хотите потратить ресурсов на нее.
        0
        >Ограничение седьмое: запуск каждого ядра сопровождается небольшой задержкой
        не про заполнение ли конвейера тут идет речь?
          +1
          Не могу сказать точно, так как не знаю, что там внутри происходит в это время. Возножно и заполнение конвейера. Скорее всего там много чего происходит в это время. Могу сказать, что оно измеряется в десятках микросекунд (50-150) и не является постоянным.
            0
            Я думаю, что речь идёт о копировании кернелов на GPU. Для многократного использования одного и того же ядра его лучше хранить в памяти GPU, чем каждый раз делать операцию вызова ядра из хостовой части. Например можно скомпилировать код ядра в CUBIN (только для CUDA) и тогда на время выполнения приложения кернелы не будут многократно копироваться.

              0
              Похоже, что мы говорим о разных задержках. Я имел в виду ту, которая происходит при запуске ядра, которое уже скомпилировано и загружено. Т.е. если Вы запустите его 100 раз, Вы потратите 100хВремя задержки, при самом первом запуске задержка еще больше. А если в OpenCL Вы запускаете программу и компилируете ядро в самый самый первый раз, так там уже время измеряется в секундах. Правда потом драйвер уже скомпилированную программу берет из кэша и все происходит быстро. (не считая того, что в нвидевской реализации есть бага:), при изменении файлов, которые инклюдятся в основной файл, драйвер использует старую версию).
                0
                Дело в том, что каждый раз, когда вы вызываете кернел из хоста, то происходит копирование, поэтому есть механизм его кеширования. Т.е. проще говоря в стандартном подходе программирования каждый вызов kernel функции равносилен операции копирования кода с хоста на GPU, если не использовать механизмы кеширования, когда данный kernel будет лежать в кеше и не дёргаться многократно. Да задержки есть и там, но они минимальны даже для 100 раз.
                  0
                  Копируется ли кернел или нет, зависит уже от конкретной реализации драйвера. Подозреваю, что какой-то механизм кэширования там есть, но это уже от нас скрыто, да и работает хорошо, поэтому лезть туда желания нет:)
                  Задержка маленькая… спору нет… пока не возникает желание запустить ядро много много тысяч раз:), как я и говорил обычно в районе 50-150мкс для моих ядер, что для 100 раз уже даст 5-15мс… с одной стороны, не очень много, а с другой не очень то и мало. У меня как раз на днях оказалось, что эта самая задержка кушала достаточное количество времени (ядра были очень очень простыми).
                    0
                    Не совсем верно, по умолчанию у вас нет кеширования kernel, поэтому данным процессом можно управлять (например CUDA API, либо через driver API). Так же, есть возможность скомпилировать cuda код в формате CUBIN, далее загрузить его в GPU и забирать его с GPU, а не с хоста. Можете посмотреть, как это реализовано в Linpack для CUDA (сейчас должен быть доступен для зарегистрированных разработчиков).
                        0
                        Похоже, что тут наши дороги расходятся:) (я про OpenCL и CUDA). OpenCL не имеет доступа к Cuda API и Driver API, что логично в целом, но является виной nVidia так как можно было бы сделать расширения. В результате, я не могу управлять размером кэша Fermi (всегда 16Кб L1) и очень Вам (CUDA программистам) завидую:). То же самое могу сказать про ядра, в OpenCL они компилируются во время выполнения и дальнейшая их судьба не контролируется (во всяком случае я не встречал ничего такого, хотя, честно говоря, не было нужды и не искал особо).
                          0
                          Да согласен, в общем-то я бы не стал винить NVIDIA за это, т.к. OpenCL стандарт и все стараются его придерживаться, а лишние расширения мешают переносимости кода (т.к. специфичны для NVIDIA только), что является основнополагающей причиной OpenCL.
            0
            Спасибо, интереснейшая статья! Совсем замечательно было бы, если бы для всех вышеперечисленных фактов были бы небольшие примеры с кодом, где это проявляется.
              +2
              Спасибо!
              Я попробую откладывать кучоки кода со значениями производительности, но не обещаю, что скоро соберется достаточно таких кусочков (в ближайшие месяца 2 пока не начну заниматься своим проектом), которые можно выложить в сети.
              +7
              Я огорчён… Думал, что будет хоть что-то об OpenCL, а вы здесь даже термины из CUDA берёте… + пора понимать, что у nVidia OpenCL это скопированная CUDA подточеная под OpenCL стандард, а так у них как всё было, так и осталось, может только стандард IEEE 754 научили.
              И приводите ограничения не к технологии OpenCL а к самой структуре графических процессоров и работы с графической памятью.

              1рвое ограничение это логичное ограничение, всегда 1 kernel спускается на 1 compute unit (субпроцессор в мултипроцессоре), если ваша программа спускается в маленьком количестве волокон, значит надо задуматься.
              К 2рому ограничении: графический чип ожидает light weighted кернелы, которые будут быстро обрабатывать только одну маленькую информацию, тй. если вам надо МНОГО информации, используйте локальную память, а только потом лезьте в глобальную, иначе вы работаете со скоростью глобальной памяти.
              С 6стым ограничением не согласен. Это можно точно также сказать, что процессор лезет в рам, когда нет чего-то в кеши. Просто это лимит, а с ним надо как-то бороться. Самый логичный способ это и есть записать в рам. Вообщем-то бы было в полне логично, если-бы это можно было предотвратит на уровне компилирования.
              Рвать много ифок в кернелы, так это зло…

              А также: OpenCL это стандард, платформа, спецификация и API. Ничего об OpenCL здесь не сказанно.

              И на собственной шкуре знаю, что не проблема перехрустеть там что-либо, проблема загрузить БЫСТРО информацию по PCI-Express в графическую карту… Я дольше ждал то, когда туда скопируется 256 мб данных, чем их обрабатывать… Даже и не спрашивайте почему 256 мб, а не больше…
                0
                Я написал, что работал с GPU основанными на CUDA в самом начале, поэтому все ограничения идут от нее.
                Для CPU все будет совсем иначе, но широкого использования CPU+OpenCL я пока не встречал, а из тех тестов, которые попадались, оно очень и очень сильно уступает SSE, так что пока драйвера не смогут делать OpenCL код сравнимый по скорости с SSE, смотреть в сторону OpenCL никто не будет. Cell'ы же штука весьма специфичная. Вот и остается только под GPU писать, хотя больше и не надо:)

                Я не совсем понял Ваш комментарий к первому ограничению. То, что надо запускать много волокон — это понятно. Но проблема именно в том, что все вычисления выполняются по 32 волокна (warp). Если будет 1млн волокон, но каждое будет выполнять разные ветки — будет медленно.

                Опять же про второе ограничение, оно связано с тем, что данные читаются блоками и получить теоретическую пропускную способность можно только читая последовательно, а это уже накладывает ограничения на типы данных и то, где данные в памяти размещены. Если у вас будет 100мб данных последовательно, то он считается быстро, если же будет те же 100мб данных, но они будут разбросаны в разных участках, все будет читаться медленно.

                Про легкие кернелы, так в том то и заключается проблема с GPGPU, что далеко не каждый алгоритм можно так вот сходу представить в виде простых кернелов. Какие-то алгоритмы можно представить, а какие-то потребуют долгой медитации над кодом. А то было бы всем уже давно счастье и считалось бы все на видеокартах:) (Заметка по этому поводу была в том лирическом отступлении, которое я урезал, надо будет его вернуть в следующих частях)

                Шестое ограничение есть везде, спору нет, только вот на GPU 63 регистра, а на CPU на несколько порядков больше. Как говорится, почувствуйте разницу. Могу предположить, что среднему программисту для реализации среднего алгоритма нужно количество регистров как раз между CPU и GPU, поэтому на CPU мы не задумываемся по этому поводу, а вот на GPU появляется дополнительная головная боль.

                Про много ифок, опять же кому как повезло с алгоритмами, не всегда можно не рвать, а если уж надо, то надо думать как это делать так, чтобы производительности не вредить (см. ограничение первое)

                Про PCI-Express и проблему передачи, опять же, у Вас алгоритм/реализация, где все уперлось в эту шину, но это не всегда так. Часто один и тот же алгоритм (часто, но не всегда) можно реализовать по разному, где-то будет упираться в шину, где-то в память, где-то в процессорное время. Вот найти оптимальную реализацию — проблема. Причем варианты могут быть такие, что для CPU никогда бы и не подумал такое делать. Например считать в 4 раза больше данных, чем CPU, но сэкономить при этом на передачи данных и получить прирост производительности.
                  +1
                  С большинством согласен, остальное разбирать не хочу, спать пора…

                  ЗЫ: Вы согласны, что программировать на графические карты намного интереснее, чем для процессоров? :-)
                    +2
                    Я всегда рад узнать, что я упустил или недопонял, так что буду рад услышать комментарии.

                    А про интересно… наверное соглашусь.
                    Хотя есть подозрение, что получение максимальной производительности на CPU — то еще веселье:). Просто обычно никто не парится, если неоптимальный код работает на сколько-то процентов медленнее, чем мог бы. А вот с GPU разница идет уже в разы и десятки раз, поэтому особого выбора и не остается, только писать оптимально, GPU плохой код не прощает:)
                  0
                  А что мешает делать асинхронное копирование?? Или вам нужен был блок в 256МБ?
                    0
                    Тогда нужен был блок > 1 ГБ :-)
                      0
                      Если данные по разу читаются, может их вообще не надо копировать? Пусть по PCIe потихоньку перетекают к GPU.
                        0
                        Зачем при асинхронном копировании вам блок в 1ГБ?
                    +1
                    Ограничение в 512 потоков возникает только если вы пытаетесь использовать все регистры (печально, что больше 63 регистров нельзя). Но если ограничение в другом месте, то может оказаться выгодным использовать меньшее число потоков. Но для того, чтобы эффективно писать на малом числе потоков нужно знать как обойти проблему номер 3.

                    Если латентность доступа к памяти 800 циклов, то латентность десяти доступов в память равна 810 циклов! Для этого нужно писать не
                    read1
                    calculate1
                    write1
                    read2
                    calculate2
                    write2

                    а
                    read1
                    read2
                    calculate1
                    calculate2
                    write1
                    write2


                    Вторая операция чтения будет выполнена не смотря на то, что данные от первой операции чтения еще не пришли. Аналогично с операциями записи. Точные правила к сожалению не известны.

                    Таким образом можно, в частности, уменьшать число потоков в двое, увеличивая в двое количество используемых регистров. Какая спрашивается тогда разница?

                    А дело в том, что иногда у вычислений с индексом 1 и вычислений с индексом 2 есть общие части. При таком способе написания алгоритма они объединяются. В результате количество регистров и вычислений часто увеличивается менее чем в двое. Можно запустить как бы «больше» потоков и получить лучшее скрытие латентности памяти или просто получить оптимизации ускоряющие алгоритм.

                    Выглядит парадоксально, но тем не менее во многих случаях из-за этого оказывается, что чем меньше потоков, тем лучше. См. статью http://www.cs.berkeley.edu/~volkov/volkov10-GTC.pdf из которой я узнал про этот метод.
                      0
                      Вы совершенно правы, маленькое число потоков — это не всегда плохо. Ограничений бывает много. Все зависит от каждого конкретного алгоритма и его реализации. Только вот понимание всех возможных узких мест — не такая уж тривиальная задача. Вообще, хотелось бы какой-то упрощенный визуальный эмулятор GPU, где можно наглядно посмотреть как куда какие запросы улетают, где кто что ждет… но это из разряда фантастики:)

                      Только к примеру надо добавить, что если
                      read1
                      будет читать из разных участков памяти, то будет латентность 800*32, так как в результате будет куча запросов к памяти и целый warp будет ждать.

                      Спасибо за ссылку! Вроде не попадалась мне эта презентация, хотя подобным методом пользуюсь. Без экспериментов никуда:)
                        0
                        Насчёт эмулятора идея хорошая и на мой взгляд очевидная. Неужели до сих пор нет?
                        У меня как бы есть опыт реализации эмуляторов процессоров, может заняться на досуге…
                          0
                          Для CUDA вроде есть, а вот для OpenCL не встречал. Если сделаете что-то юзабельное, да с возможностью отладки, цены Вам не будет:)
                          Я по возможности делаю свои ядра такими, чтобы на CPU запускались и компилировались студией, но всему есть свои пределы. Вообще, хотелось бы что-то простое, даже не симулятор, а утилитку, которая бы для каждой строки показывала сколько регистров съедено да сколько операций совершено, сколько запросов к памяти отправлено. Даже такая статистика бы пригодилась.
                            0
                            Зачем вам эмулятор графической карты на процессоре у OpenCL? На CPU ведь всё работает «точно также» как и на GPU… Только ограничения другие (group_size (GPU: 256, 256, 256 vs CPU: 1024,1024,16), memory, итд..)… + нет быстрого спущения кернелов…
                            А для конкретного просмотра как кернелы компилируются, так можно воспользоваться «AMD APP KernelAnalyzer»…
                              0
                              Есть несколько ответов на этот вопрос:
                              1) У меня нет ничего от AMD, так уж вышло и вряд ли изменится, а архитектуры таки у них разные,
                              2) Точно также Вы и сами в кавычки поставили,
                              3) Из тех утилит, которыми я пользовался для nVidia не попалось ничего, о чем можно было бы сказать, что этого достаточно.

                              Мне хочется видеть какая команда сколько каких ресурсов может потратить. Я просто хочу что-то наглядное. Пусть даже статическое, но под nVidia и удобное. Но это уже так… из серии чего бы хотелось…

                              Что реально нужно, так это дебагер (для Windows+nVidia+OpenCL)
                      0
                      Интересная статья! Обязательно пишите продолжение! Было бы очень приятно, если бы в дальнейшем были примеры с кодом, а повествование рассматривало и особенности AMD карт.

                      На мой взгляд, не смотря на всю эту проблематику — не всё так грустно. Конечно, для сложного кода построение программы усложняется на порядки по сравнению с CPU, но для простых операций (применить простой фильтр к изображению, произвести простые матричные расчёты) производительность может разогнать даже не специалист. При этом программа будет работать достаточно быстро и на Nvidia и на AMD.
                        0
                        Как будет время, обязательно продолжу. Рабочий код сейчас показать не могу, но, опять же как будет время, попробую сделать несколько тестовых примерчиков, а то мне самому интересно проверить некоторые вещи. С AMD сложнее… у меня есть кучка карт от nVidia и ни одной от AMD (нвидия как-то добрее, например прислала нам Quadro 6000 бесплатно (при стоимости в несколько килобаксов) для рисерчей). Но если попадется, попробую.

                        А про сложный и простой код правда. Только вот не так уж много в реальных приложениях этих самых простых алгоритмов, а все сложное уже должно оптимизироваться под каждую архитектуру… тут с до-Fermi на Fermi не перенесешь особо (без потери производительности относительно максимума), а на другую совершенно архитектуру еще хуже.
                          +1
                          Это та же проблема и с процессорами. Вроде новые процессоры, быстрее-выше-сильнее… но на деле выявляется куча проблем, которые надо решать либо оптимизацией компилятора, либо методом распараллеливания с учетом потери относительной производительности.
                          У всего этого есть один большой плюс — требуется постоянная работа на алгоритмами и их оптимизацией, что в конечном итоге может выйти в хороший прирост (как производительности, так и денежный).
                        0
                        Действительно графические процессоры не работают с числами типа double?
                          0
                          В большинстве GPU не поддерживают double, достаточно посмотреть любой современное 3d API, чтобы убедиться в этом ). Хотя ряд архитектур GPU (в частности Fermi) имеет нативную поддержку double'ов.
                            0
                            это хорошо, значит в некоторых задачах можно переходить с MPI, потому что, например, для преобразования Фурье, распределенная система никак не подходит.
                              0
                              Есть только маленькая проблема — на compute capability 2.0 производительность double в 8 раз ниже, а в 2.1 — в 12 раз. В результате распараллеливание + SSE часто дает лучшие результаты, чем видеокарта.
                                0
                                интересно, с чем связана такая медленная работа с double, ведь Fermi выпускается в большей степени для научных расчетов, а в них без двойной точности ну совсем никак.
                                  0
                                  Потому что иначе карты не будут покупать геймеры. Ведь в 3d-графике нужны расчеты с float.

                                  Если бы ученых было столько же, сколько геймеров, были бы видеокарты которые float считать не умеют. Вычисления с double при этом все равно не достигли бы такой же скорости, поскольку они требуют больше места на чипе, а следовательно вычислительных блоков можно разместить меньше.
                                    0
                                    конечно странно, та же Fermi стоит в несколько раз дороже обычной видеокарты. Многие вычислительные центры перешли бы со временем к графической платформе. В вычислительном центре РАН, например, такой вопрос был на повестке. При таком раскладе, массового использовании GPU в научно-инженерных расчетах не будет, хотя идея сама по себе хорошая, насколько я понял ее сейчас подхватил интел.
                                      0
                                      Fermi и есть обычная видеокарта. У меня в ноутбуке стоит мобильная версия Fermi. Может вы путаете ее с Tesla?

                                      В науке не всем обязательны double. Я так вообще чаще всего вообще с целыми числами на видеокарте работаю. Судьба double на GPU пока не ясна. Компании пока лишь пробуют землю выпуская пробные версии, чтобы понять что же нужно людям. Если окажется, что на этом рынке есть большие деньги, то сделают и видеокарты, эффективно работающие с double. Так что пишите статьи о том, что получается хорошо, а что получается плохо и возможно вас услышат.
                                        0
                                        да, я имел ввиду Tesla!
                                          0
                                          Стоимость Tesla меня тоже шокирует. Я не могу ее объяснить.
                                            0
                                            как мне объяснили, Nvidia дает гарантию, что Tesla не будет глючить в расчетах, в отличии от бытовой карточки
                                          0
                                          при интегрировании диффуров, если много шагов считать нужно, то без double никак, а это очень частая задача. Суммирование рядов, интегралы и тд, тоже требуют double
                                    0
                                    В 8/12 раз ниже по сравнению с чем?
                                    С single, а не CPU.
                                      0
                                      Угу.
                                        0
                                        Тогда в чем проблема?
                                          0
                                          100 кратное ускорение становится 10 кратным, которое перекрывается 4 ядерным процессором с SSE.
                                            0
                                            Что правда, то правда. Только вот получить больше 6 CPU ядер в среднем компьютере весьма и весьма тяжко, а получить 4 GPU очень даже легко, каждая вторая материнка 2 PCIe слота имеет, куда две GTX590 запихнуть можно за сравнимые (с 6 ядерным процом) деньги.
                                            А если дальше посмотреть, все еще веселее… в плане цен становится…

                                            Для сравнения производительности могу сказать, что GTX580 обгоняет одно ядро i7-2600 раз эдак в 30-130 (все зависит от алгоритма, данных итд итп).
                                              0
                                              Угу. Поэтому компьютеры на видеокартах имеют смысл.
                                                0
                                                На чистых видеокартах не имеют… кто-то помню извращался на ферми что-то х86 симулировал, но жутко медленно. А вот использовать GPU как сопроцессор, очень даже хорошо.
                                              0
                                              Не совсем так. Ускорение само по себе не является константным, поэтому говорить о 100 или 10 кратном увеличении имеет смысл лишь тогда, когда код полностью адаптирован на GPU и результаты получены(зачастую это редкие случаи, т.к. алгоритмы не всегда поддаются распараллеливанию). И уж тем более перекрыть 4-х ядерным процессором это нельзя, ибо всплывает куча нюансов, на которых процессор просидает. Вопрос кол-ва double и single производительности — это вопрос баланса цены.
                                        +1
                                        Все несколько интересней на самом деле.
                                        NV compute capability <1.3 (если не ошибаюсь) не умеют работать с double в принципе.
                                        NV compute capability <2.0 Имеют один double блок на мультипроцессорв, в результате у них примерно в 10 раз меньше скорость вычисления double чем single
                                        NV compute capability 2.0 может работать с double в ДВА раза медленнее, чем с single (и это правда для Tesla и Quadro), но производительность GeForce специально ограничена еще в 4 раза, дабы люди покупали Quadro.

                                        Про AMD не знаю.
                                  –1
                                  Да там есть одна проблема — нужно мыслить параллельно, т.е. в буквальном смысле: забудьте чему вас учили до этого! Сам программировал для GPU на OpenCL и могу с уверенностью сказать — там все завязано на низкоуровневую оптимизацию распределения памяти. А что вы хотели? Думали, что х200 получить так просто, как написать Hello World на C#?

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое