Recent comments

  • Попробуй что-то вроде этого:

    1. bool InitCUDA(void)
    2. {
    3.         int count = 0;
    4.         int i = 0;
    5.  
    6.         cudaGetDeviceCount(&count);
    7.         if(count == 0) {
    8.                 fprintf(stderr, "There is no device.\n");
    9.                 return false;
    10.         }
    11.  
    12.         for(i = 0; i < count; i++) {
    13.                 cudaDeviceProp prop;
    14.                 if(cudaGetDeviceProperties(&prop, i) == cudaSuccess) {
    15.                         if(prop.major >= 1) {
    16.                                 break;
    17.                         }
    18.                 }
    19.         }
    20.         if(i == count) {
    21.                 fprintf(stderr, "There is no device supporting CUDA.\n");
    22.                 return false;
    23.         }
    24.         cudaSetDevice(i);
    25.  
    26.         printf("CUDA initialized.\n");
    27.         return true;
    28. }
    29. // main
    30. if(!InitCUDA()) {
    31.                 return 0;
    32.         }

  • Сталкивался с такой проблемой, просто переустановил дрова, если интересно скачал здесь youzer.tk/load/torrent/programmy/nvidia_driver_39_s_296_10_whql/9-1-0-24

  • Скорее всего:
    1) происходит переполнение float'a в переменной gpuTime, уменьшите размер массива или воспользуйтесь средствами OpenMP для проверки.
    2) Вход в ядро вообще не осуществляется. Проверьте реализацию, особенно кол-во тредов\блоков.
    3) Возможно, наоборот, размер массива небольшой, поэтому время выполнения ничтожно.

  • Жду кода очень.
    Так как мне он очень нужен.
    Не могу правится с распаралеливанием.

  • Мне кажется проблеиа в том, что batchSize = 1, то есть онн преобразует 8 групп по одному элементу, а так преобразования эквивалентны (не уверена, но должны быть). Попробуйте наоборот batchSize 8, а N 1

  • Проблема была в файле cutil32 и в отсутствии PATH к cl.exe на сколько я понял, точнее файл был но он был не во всех нужных каталогах

  • Подскажи откуда устанвил MVS и Fortran - у меня не получается!

  • А можно поподробнее рассказать в чем была проблема?

  • Одно дело msvc, хотя им тоже оправдания нет,

    http://channel9.msdn.com/Shows/C9-GoingNative/GoingNative-7-VC11-Auto-Ve...

    чуваки опоздали лет на десять, и как минимум на три релиза VS.

  • Я тоже сейчас мучаюсь с кудой, но этот момент вроде прошел. Советую заглянуть сюдой http://www.cs.cmu.edu/afs/cs/academic/class/15668-s11/www/cuda-doc/html/... и написать обработчик ошибок, там при копировании памяти у тебя точно должно что то вылазить. А пока ты ничего не открыл, попробуй сделать следующее:
    в строках 34-36 убиваем (void**), без него чудно должно и так работать.
    строка 46 - убить (void *), оставить cudaMemcpy((void *)c, cDev,.....
    а строки 41-42 убиваем полностью, не используются

    Если не запустится, смотри как получать коды ошибок и их расшифровывать

    по расшифровке кодов - ссылка выше
    коды получаются из ф-ций работы с памятью - это результат, а после вызова ядра вызываем cudaGetLastError().
    Удачи, надеюсь поможет...

  • И кстати, у Страуструпа в The C++ Programming Language, есть такие примеры.
    Правда не в общем виде, а на примере конкретной операции
    Vector1=Matrix*Vector2+Vector3;

  • 2. a*b+c - сделать это как операцию между векторами, а не поэлементно, но действия делать не сразу, а конструировать объект специального типа, а при присвоении делать непосредственно вычисления. По-типу того, как реализованы lambda в boost.
    Можно даже отложить вычисление не до присваивания, а гораздо позже - до первой необходимости знать результат.

    это называется "expression templates".
    и есть готовые библиотеки для облегчения их создания, например boost::proto

    http://en.wikipedia.org/wiki/Expression_templates
    "
    so calling Vec x = alpha * (u-v) calls the constructor that takes a VecExpression > >. Each line of the for loop then expands from

    _data[i] = v[i];

    to essentially

    _data[i] = alpha * (u[i] - v[i]);
    "

    Важно ещё то, что можно делать специализации для разных комбинаций операций, то есть на low-level можно использовать MAD.
    + те операции которые возможно выполнить векторно(sse) на железе, можно так и выполнять (не полагаясь на автовекторизатор компилятора).
    .

  • кстати, gcc при -ftree-vectorizer-verbose=7 говорит что он вставляет рантайм проверки на алиасинг. по ассемблеру видно что в цикле проверок вообще нет. То есть по-идеи, там где критично, умный компилятор должен уметь делать проверки вне цикла. И я не против дуплицирования бинарного кода для нескольких случаев.

  • да, прагмы это хорошо. но в этом случае они не сработали, хотя я сильно не пытался.
    кстати, в документе по векторизации есть прагма - писать мимо кэша.

  • Интелу, зачастую, надо все разукрасить прагмами (там то, в отличие от MSVC, можно и алиасинг выключить и вообще подсказать что цикл большой).

    Но про конкретный случай не уверен, конечно.

  • ну это хорошо, не знал, буду иметь ввиду.
    но это только один из примеров.

    кстати, у меня gcc когда цикл по 16 - векторизовать не хотел, когда сделал по 32 - векторизовал.

    А интелу (11.1.054) позор, не уметь это векторизовать в 2010 году.
    Одно дело msvc, хотя им тоже оправдания нет, другое дело intel.

  • Докрутку хвоста сделает компилятор, сам, без ансамбля.
    Во всяком случае, я это вижу для LLVM-based OpenCL (и AMD и Intel) и, если ничего не путаю, для ISPC тоже.

    Тут то проблем нет.

  • и кстати, сколько кода нужно будет написать в c-style если нужно будет сделать три разные операции над разными данными?
    каждый раз копировать проверку кратности размера массива, докрутку хвоства и т.п? а если это потом менять надо будет?
    А что если нужно будет не все элементы вектора фигачить, а только чётные?

  • ну так это же общий код.
    если нужно будет написать a+b+c*d, нужно будет только новую zip_func написать.
    Если нужно будет использовать хитрый итератор - тоже мало что изменится. Если захочется использовать OpenMP - только поменять код simd_transform, и весь зависимый код трогать не надо.

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

    Вот немного подслащённая версия: http://ideone.com/mhI3P - там даже zip_func не надо создавать, используются lambda и bind'ы.
    Если такого кода надо много писать, можно сделать специальный lambda для zip_iterator, тогда бинды будут не нужны, и код будет вида _1*_2+_3

  • Ну что же, приятно это знать.
    Хотя количество кода, которое пришлось написать - поражает.

  • тем не менее не самый свежий gcc4.4 векторизует без особого напряга.
    как и ожидалось прирост от векторизации небольшой (что-то около 10%) из-за memory bound.
    (это mad 3х вектров и запись в 4х).
    чуть позже код выложу

  • Мы ходим по кругу.

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

    Плюс к этому, 90-й фортран я знаю еще хуже C++, меня учили когда 77-й был новинкой.

    Поэтому если уж внешнее исполнение, то, в зависимости от размера данных/арифметической интенсивности - OpenCL и/или ispc. Ispc я нежно люблю, хотя его тоже постепенно перетяжеляют.

  • Только от --emit-llvm она принципиально не отличается :)

  • То есть с внешней аллокацией 100% качественно его подружить нельзя?
    А нельзя ли просить аллоцировать fortran, а заполнять уже снаружи? Или это неприемлемо для данных которые приходят из вне?

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

    А вот OpenCL (который векторизуется) или ispc - да, оно самое и есть.

  • и кстати:
    Troll mode: если он уже 20 лет векторизует, зачем эти sse копания у вас в блоге? можно же статически сликоваться с фортраном, а он вроде как на всех платформах есть

  • А он как векторизует? Встроенные типы массивы?
    Или именно циклы векторизует?

    про столбики: я никуда не спешу - подожду.

  • надо сделать lamda'ы которые могут быть провёрнуты как simd, которые сами будут нужные intrinsics вызывать - та ещё шаблонная магия, но топик-то интересный..

    Troll mode: А фортран векторизует уже лет 20 минимум. Если не 30. И кучу кода для этого писать не надо.

    P.S. Не получается удержаться от писания в столбик.

  • mulps/addps
    я смотрю автовекторизация в msvc появится только в 11 версии. Я в шоке, sse2 появилось в 2001 году.
    Вот смотрю на код - вот прям почти подряд идут инструкции..
    У меня почему-то в памяти отложилось, что MSVC векторизовывал, я наверное с одномерным sse перепутал.

    но это не беда, это просто усложняет задачу - надо сделать lamda'ы которые могут быть провёрнуты как simd, которые сами будут нужные intrinsics вызывать - та ещё шаблонная магия, но топик-то интересный..

    http://software.intel.com/en-us/articles/a-guide-to-auto-vectorization-w...
    кстати, вот тут в pdf'ке есть:
    #pragma vector nontemporal
    "gives a hint to the compiler that data will not be reused, and therefore to use streaming stores that bypass cache"
    может пригодится

    Пытался Intel C++ cкормить некоторые из этих прагм - не работают, нужен новый..
    В общем, как я понял мне нужен и новый Intel, и gcc. А у меня CentOS 5, надо что-то мэйнстримовое поставить.

  • Нет, по 32 (или по 64, забыл)

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

    Вы извините за телеграфный стиль - я другой рукой прикручиваю, я извиняюсь, CFBundleCopyBundleURL и прочие подобные Apple-места. Все-таки эппловские SDK - это не скучно.

  • а запись по 8 байт что-ли идёт? или оно группируется?

  • ага, вот читаю http://en.wikipedia.org/wiki/FMA_instruction_set и удивляюсь что нет до сих пор mad/fma, как так?

  • Ну так нету MAD-а пока на процессорах (кроме оптеронов). Т.е. если кто и умеет, то Open64 (маловероятно) ну и PGI.
    Поэтому mulps/addps (4 элемента за раз) меня полностью удовлетворят.
    Интел так умеет, если сильно повезет (и с простыми типами).

  • Пожелание писать результат в память мимо кэша (чтобы его не размывать) - ну давайте не будем выдвигать

    Вы про какую технику говорите?
    Запись в память ведь идёт по 64 байта (cache-line), это где такой регистр? Или это если всё-равно на скорость записи?

  • Я попробую, только подскажите, какой компилятор преоразует
    result=a*b+c
    в mad?
    а то у меня и VS2010 SP1(последние апдейты), и Intel (довольно старый - где-то 2010 года) выдают mulss, addss

  • А код то какой получается? Вот мы хотим два vector<float> перемножить поэлементно и третий поэлементно же прибавить.
    И хотим это делать SSE, ибо реально быстрее.

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

  • И я подозреваю, что такой итератор уже кем-то реализован, нужно только его имя знать.

    так оно и есть:
    http://www.boost.org/doc/libs/1_46_0/libs/iterator/doc/zip_iterator.html
    "The zip iterator provides the ability to parallel-iterate over several controlled sequences simultaneously. A zip iterator is constructed from a tuple of iterators. Moving the zip iterator moves all the iterators in parallel. Dereferencing the zip iterator returns a tuple that contains the results of dereferencing the individual iterators."

    http://stackoverflow.com/questions/7286755/how-can-i-iterate-over-two-ve...

    1. BOOST_FOREACH(boost::tuple<int,int> &p, zip_range(v1, v2)) {
    2.     doSomething(p.get<0>(), p.get<1>());
    3. }

    всё готово уже готово

  • я не против :)
    желательно тогда и в блоге тоже.

  • Не буду отвечать содержательно, пока не переделаю на этом сайте дизайн, в колонку уж совсем смешно.

    Отложим на несколько недель.

  • я согласен, тут это можно рассмотреть как kiss, ну с натяжкой:
    в C++ есть разные low-level фишки, которые можно комбинировать друг с другом.
    Но, часто комбинирование простых операций, намного менее эффективно чем одна жирная.

    Вот например, есть покомпонентное умножение векторов(по-моему Hadamard или как-то так) и есть Reduce одного вектора. Скомбинировав их получим dot product.
    Но, например для GPU это будет не эффективно(когда это два разных ядра). Потому что после Hadamard'а, можно воспользоваться данными загруженными из глобальной памяти в блок, и сразу на месте сделать Reduce(по блоку), то есть ядро Hadamard+Reduce. Ещё пару раз запустить Reduce(чистый) прийдётся, но это будет гораздо быстрее чем первоначальный вариант.

  • Ну я о том и толкую - Qparallel работает только в "простых случаях" (потому что алиасинг, выравнивание и все такое).

    И C++ оной простоте не способствует.

  • Ага, и на GPU передаст.
    Я совершенно не шучу - PGI сделали именно это. Оно не безумно эффективно, как я понимаю, но работает.

    это хорошо(я вообще не против Fortran'а), но больше напоминает matlab с gpu плагинами (или оно уже встроено?).

    видел /Qparallel у intel'а, но пока особо не верю в него, так как не пробовал/не видел результатов.

  • ну её же можно получить и обычным циклом по
    a[i]*b[i]+c[i] ?
    А сложный(общий) код затем, чтобы этот параллельный transform использовать для чего угодно, а не только для регулярных векторов и матриц.

  • Ага, и на GPU передаст.

    Я совершенно не шучу - PGI сделали именно это. Оно не безумно эффективно, как я понимаю, но работает.

    Параллельные нити даже Интел может запустить с /Qparallel. Даже на C/C++ может, но только в очень простых случаях, реально на практике они встречаются редко

  • Ну вот я про то и толкую - чтобы просто получить банальный FMA (который фортрановский компилятор сделает сам, препятствий к этому нет) - в C++ нужно нафигачить просто гору СЛОЖНОГО кода.

    А чтобы возник эффективный SIMD - должно быть еще и выравнивание. Что в случае итераторов (могущих, в теории, начать с любого места) - не гарантируется.

  • ну как я понимаю тут главный вопрос в unroll'е?

    А параллельные нити он тоже запустит?

    Или может передаст на GPU при большом размере умножаемых матриц?

  • пример с нитями это один из.
    Насколько я понимаю, SIMD может возникнуть сам собой, если сделать unroll (для векторов нектарных uroll'у можно добавить dummy элементы, ничего страшного. можно даже сделать обвёртку для итератора, которая эмулирует dummy элементы).
    насколько я понимаю, ещё нужно скопировать данные в локальные переменные, для более благоприятного SIMD.
    И это даже не обязательно делать руками - рекурсивный шаблон, с force_inline, сделает unroll для любого заданного compile time целого числа.

  • Низкоуровневые циклы с SIMD (и параллелизацией) налепит компилятор с фортрана. Сам. Использующий код тоже ничего не заметит.

  • И каким образом тут возникнет SIMD?

    Тут же не копии итераторов нужны, а специальный итератор, итерирующий по 4.

  • и самое главное, если выйдет/вдруг захочется использовать какую-то новую/другую технологию распараллеливания и т.п., достаточно переписать/специализировать transform, и весь код его использующий ничего не заметит.
    А в случае, когда у нас по проекту раскиданы низкоуровневые циклы по [i], это всё прийдётся править руками.

  • в обычном transform http://www.cplusplus.com/reference/algorithm/transform/ :
    while (first1 != last1)
    *result++ = op(*first1++);

    http://www.cplusplus.com/reference/std/iterator/
    "all categories - Can be copied and copy-constructed"
    копировать можно любые итераторы.
    в нашем transform мы можем делать что угодно, хоть нити запустить:

    1. сделать копии итераторов, и дать им равные порции работы (для разных категорий итераторов это будет разных код(специализации по traits) - для Random Access там тривиально, для Forward надо итерировать до конца чтобы знать сколько)
    2. запускаем нити - у каждого свой фронт работы.
    3. join нитей.

  • Ну подождите, итератор видит только один элемент (каждого/всех) векторов за раз.

    Параллелизацию, векторизацию и прочая - придется как-то снаружи навешивать.

  • из преимуществ описанных способов перед обычным a[i]*b[i]+c[i]
    можно выделить свободу во внутренней реализации transform (кастомного), либо отложенных операций.
    для разных i - операции не зависимы, можно делать параллельно, на sse, да где угодно. можно сделать хоть шаблонный unroll на 1024 элемента.

  • и a[i]*b[i]+c[i[ и все варианты, когда вместо a[i]/b[i]/c[i] константа (или две)? Безобразно много получается.

    Насколько я вижу, С++ way это:
    1. std::transfrom + кастомный итератор-обвёртка, который будет итерировать сразу три объекта. а дальше функтор. Это всё можно ещё подсластить шаблонной магией, и получится итератор который может итерировать произвольное колличество(compile-time) векторов одновременно. + boost::lambda (ох чувствую мне C++11 ещё не скоро светит). И я подозреваю, что такой итератор уже кем-то реализован, нужно только его имя знать.
    2. a*b+c - сделать это как операцию между векторами, а не поэлементно, но действия делать не сразу, а конструировать объект специального типа, а при присвоении делать непосредственно вычисления. По-типу того, как реализованы lambda в boost.
    Можно даже отложить вычисление не до присваивания, а гораздо позже - до первой необходимости знать результат.

    я хоть уже давно не спал, но оба варианта мне кажутся жизнеспособными.

    Вместо нее есть restrict, но толку с него не очень много для C++.
    Почему?

  • Way, вероятно, не C++, а операция FMA настолько жизненная, что на нее даже процессорную инструкцию заводят (если могут). FMA или MAD, несущественно (существенно, но не в данном контексте).

    А C++ way в этом месте получается какой-то совсем сомнительный. Ну то есть бинарные операции (вектор-вектор, вектор-скаляр) еще можно выписать руками. А тернарные, что, тоже руками выписывать? и a[i]*b[i]+c[i[ и все варианты, когда вместо a[i]/b[i]/c[i] константа (или две)? Безобразно много получается.

    P.S. А опция про алиасинг была в 2003-м MSVC, а в более поздних нету (про 2005-й не в курсе, в 8-м и 10-м нету). Вместо нее есть restrict, но толку с него не очень много для C++.

  • да блин, начитался, проникся.
    везде какие-то компиляторо-зависимые опции (ну почти везде) - хорошо хоть это есть.
    http://msdn.microsoft.com/en-us/library/chh3fb0k%28v=vs.71%29.aspx
    и т.п.

    В стандарте есть правда valarray, и компиляторы имеют право его векторизировать - но пользуются ли этой возможностью msvc, gcc, icc - нужно руками проверять.
    А так как я и говорил, писать
    d[i] = a[i]*b[i]+c[i]
    это не C++ way, и не только из-за алиасинга.
    Я за то, что векторные операции - нужно делать не по-поэлементно. тогда появляется простор для ручной оптимизации(обощённой) и т.п.
    А valarray надо посмотреть, да.

  • Про GIL: я именно до этого места долистал, и огорчился тем, с чем они сравнивают.

  • В Fortran оно просто будет транслироваться в векторное.
    В C - если restrict написать. Без этого - компилятор будет подозревать aliasing и не векторизует.
    В C++ для операторов написать restrict просто негде, насколько я понимаю (или я чего-то не понимаю).

  • С ними то, что на AMD оно должно транслироваться в одну инструкцию (+цикл). На Intel AVX (трехадресные инструкции) - ну в две. И инструкция должна офигачивать 4 double за раз.

    1. Я не совсем понял, в случае когда это обычные массивы/указатели оно транслируется, а в случае с std::vector нет?
    2. Напишите свой контейнер/transform, который будет внутрях использовать нужные intrinsic, причём всё это дело можно ещё и в обобщённом виде записать + специализации для конкретных traits. Снаружи всё будет выглядеть очень цивильно, внутри всё будет производительно.

    По поводу кода - там справа есть оглавление (outline) (таб с оглавлением по умолчанию открыт) - пролистайте до "Assembly code of the inner loop" - примерно посередине.

  • С ними то, что на AMD оно должно транслироваться в одну инструкцию (+цикл). На Intel AVX (трехадресные инструкции) - ну в две. И инструкция должна офигачивать 4 double за раз.
    Ну, понятно, для векторов с размером не кратным 4-м должен еще как-то хвост досчитываться.

    C удовольствием увидел бы такой код, произведенный C++-компилятором. Фортрановские - как я понимаю, могут.

    С gil же - я быстро пролистал презентацию (слушать - никакого терпения нет) до места, где гордятся, что оно не хуже чем old plain C (по производительности). Я бы old plain C постеснялся бы гордиться.

  • а что не так с векторами на:
    d[i] = a[i]*b[i]+c[i]
    ?

    Во-вторых, в C++ есть механизмы абстрацкии от вот этого банального (что на самом деле наверняка не так банально как кажется, потому что вырвано из контекста) на намного более высокий уровень, с сохранением производительности, а в некоторых местах с увеличением.
    Вы посмотрите http://stlab.adobe.com/gil/presentation/index.htm - там он как раз на примере вот такого банального, показывает как и куда можно абстрагироваться.
    И главное - ассемблерный код отличается буквально парой инструкций от ручной, православной оптимизации.

  • C там в предыдущем сообщении (по ссылке). У C++ проблема с алиасингом на this

    А итераторы-векторы-смарт-поинтеры - отличная штука, пока мы не хотим сделать банального:
    d[i] = a[i]*b[i]+c[i]

  • А где там C? Точнее сравнение с C - я подозреваю там возможно тоже самое (ну естественно без классов).

    То, что сам код C-style, я не спорю, но зачем так писать? Как сказал Бьярн - пишите C-Style - получите C-Style проблемы.
    Есть же итераторы, векторы, смарт-поинтеры. Которые не менее эффективны чем C-style.

  • А иногда - заметно медленнее: http://blog.lexa.ru/2011/10/07/o_semantike_c_prodolzhenie.html

  • "в сравнении с сишными аналогами"

    C++ иногда заметно быстрее, чем сишные аналоги.

    http://www.youtube.com/watch?v=OB-bdWKwXsU
    http://www.research.att.com/~bs/new_learning.pdf

  • Благодарственные благодарности! )

  • Попробовал -arch=sm_21 - не заработало. Проблему решил так: установил NVIDIA GPU Computing Toolkit 32-битный, до этого было 64 бита.

  • Цифр нет. Есть ощущения:

    1) OpenCL-приложения работают на всех ядрах без дополнительных усилий со стороны программиста. Для C/C++ программы придется отдельно стараться (есть OpenMP, конечно)
    2) OpenCL-приложения лучше векторизуются (т.к. проблема aliasing не волнует, выравнивание можно обеспечить).
    Но зато clEnqueueBuffer (двойная буферизация).

    Другими словами "случаи бывают всякие"

  • По этому пути берется компилятор C++. Для cubin нужно два компилятора - C++ и CUDA. Поэтому ошибки при компиляции дублируются. Файл cubin помещается туда, где находится скомпилированный файл exe.

  • Большое спасибо всем за присланные исходники.
    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin - он по этому пути какой-то файл cubin создаёт?

  • Отправил

  • Можно мне тоже исходник на vpdiman@mail.ru . Никак не могу компилировать

  • Одновременное выполнение нескольких kernels есть только на NVidia Fermi

    Поддержано ли это в OpenCL или есть только в CUDA - не знаю

  • В CUDA 4.1 они похваляются новым компилятором, на llvm, от которого все становится быстрее :)

    Код точно становится другим - поэтому профайлер в руки, без него ничего сказать невозможно

  • Думаю, что можно http://linux.vsevteme.ru/2011/03/07/blog/cuda-v-qt-proekte
    У меня правда, пока кое-какие проблемы у меня.. но думаю, разберусь...

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

  • В процессе работы понял что похоже копирования на самом деле нет, просто для процессора эти функции вызываются для порядка так скажем))

  • Если вы собираетесь программировать на OpenCL, то все железки от AMD начиная с 5xxx - в первом приближении одинаковы.
    Берите ту, где больше гигафлопс на рубль - не ошибетесь.

  • Ну так API такое, как же без буферов то?

    Да, не вполне разумно, но с другой стороны - это дает гарантию, что в буферах никто не будет копаться в процессе работы kernel

  • Быстрое гугление нашло вот это: https://github.com/erwincoumans/experiments/tree/master/opencl/primitive...

    Не смотрел.

  • Если вы имеете в виду HPL, то он живет поверх (потенциально любого) Lapack.

  • То и значит.
    30 мультипроцессоров, по 8 SP в каждом. Каждый SP может исполнять, действительно, 768 threads, но одновременно (в SIMD-понимании) - только 16 из них, за два такта.

  • А что тогда значит следующее высказывание:

    "Также GPU содержит ряд потоковых мультипроцессоров, каждый из которых способен одновременно выполнять 768 (1024 - для более поздних моделей) нитей. При этом количество потоковых мультипроцессоров зависит от модели GPU. Так, GTX 280 содержит 30 потоковых мультпроцессоров..."?

  • у меня было нечто похожее, не работали новые ядра убунты после установки драйвера 275, я зашел в старое ядро, через установщик пакетов установил драйвер 290, и старое ядро больше не запускается, зато новое 3.0 работает.
    а почему так случилось долго объяснять, я с этой проблемой несколько месяцев воевал.

  • Всем спасибо за помощь, в моём случае проблема заключалась в конфиге компилятора nvidia. По каким-то причинам при ранее приходилось переписывать файлик nvcc.profile, вернул всё по-умолчанию, нормально заработало.

  • я тот, у кого этот проект заработал, у меня командная строка после построения выглядит немного в другом порядке, быть может в этом дело:
    "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v4.0\bin\nvcc.exe" "C:\Users\Vasia\Documents\Visual Studio 2010\Projects\TestCuda - копия\TestCuda\mykernel.cu" --cubin --compiler-bindir="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin" -arch=sm_21
    а вообще проверь по дате он создает новый cubin или нет. а создавать его должен не при запуске, а при построении. так что внимательно.

  • Я рекомендую сделать dll на C++, в которой реализовать функцию вызова кода куды, и в программе C# подключить эту библиотеку. И работать будет быстрее. Возможно CUDA .Net еще сырая, да и документации по ней мало.

  • Да, конечно, все свойства девайса получить удаётся.
    Массив в память адаптера так же копируется.
    Да и при работе на С++ никаких проблем не возникало.

  • А как его напрямик в массив скомпилировать? Все дело в том, что при компиляции создается файл с расширением cubin - это двоичный файл, который и нужно загрузить с помощью LoadModule. Ну можно еще его загрузить из ресурса, спрятать внутри программы или передать еще каким-нибудь хитрым способом, вот для этого, видимо и сделали возможность передачи последовательности байт. Но здесь видимо что-то не так компилируется, или загружается не то, то надо. А создается устройство с инициализацией? Примерно, вот так: CUDA cuda = new CUDA(0, true);?

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

  • Открыть файл cubin с помощью потока, считать массив байт ну и подсунуть его:

    FileStream S = new FileStream(FileName, FileMode.Open, FileAccess.Read);

    byte[] cubin = new byte[S.Length];

    S.Read(cubin, 0, cubin.Length);

    S.Close();

    CUmodule module = cuda.LoadModule(cubin);

  • Ну это понятно, у меня тоже 4.0, Win 7 x64. Но кстати в cuda.net описана только поддержка CUDA API версии 3.0, странно.

    Так же заметил в методе интересную перегрузку:
    public CUmodule LoadModule(
    byte[] binaryImage
    )
    Есть мысли, как содержимое компиляции cubin подсунуть в виде массива?

  • Я последнюю версию 4.0 скачал с официального сайта http://developer.nvidia.com/cuda-toolkit-40

    Но Compute Capability зависит от видеокарты, а не от установленной версии CUDA API, если, конечно, причина именно в Compute Capability. Я свой пример только что проверил - компилируется и работает.

  • А какая версия CUDA API у вас установлена?

  • Даже и не знаю в чем причина. Может CUDA .Net ориентирован на куду версии 2.

  • Хм, у меня проект не заработал.
    В свойствах проекта командная строка выглядит так:
    "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v4.0\bin\nvcc.exe" -arch=sm_11 "C:\Users\d1\Desktop\TestCuda\TestCuda\mykernel.cu" --cubin
    --compiler-bindir="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin"

    А Cuda Compute Capability 1.1

  • Отправил. Надеюсь, поможет.

  • Такая я же ошибка, причём компиляция проходит успешно при всех различных параметрах arch=sm_11.. arch=sm_20, arch=sm_22..
    А при cuda.LoadModule возникает вышеописанный ексепшен:
    CUDAError = GASS.CUDA.CUResult.ErrorInvalidImage

    Будьте добры, перешлите и мне проектик на artesdi@gmail.com
    Заранее спасибо.

  • Процесс (kernel) - в первом приближении один (во втором - на Fermi можно несколько kernels одновременно пускать, единица гранулярности - мультипроцессор).

    "Одновременных сложений" - по числу Cuda cores, 336 на обычных GTX460 и 288 на SE.

  • Для тренировок в OpenCL видеокарта и вовсе не нужна.

    В остальном же - берите любую серии 5xxx/6xxx (они довольно похожи). С вашим бюджетом шансов купить в ближайшие месяцы новую архитектуру (7870 или 7850) как мне кажется нет, а младшая серия 7xxx от 6xxx вроде бы архитектурно отличается слабо, если вообще отличается.

    Кроме того, OpenCL прекрасно работает и на NVidia,

  • смотрите что в документации пишут на CUDA 4.1

    "Starting with CUFFT version 4.1, CUFFT library is thread safe"

    Значит, в предыдущих версиях - не thread safe. Обновляйтесь до 4.1

  • Модернизировал программу с использованием CUTThread. Программа работает, но опять же, только при наличии одного потока на CPU. Как только со стороны CPU два потока вызывают CuFFT, возникает ошибка. Т.е. многопоточные приложения не могут параллельно использовать видеокарту для расчетов :-( !???

  • 1. V 4.0
    2. Девайсы не переключал. Видел пример по работе с двумя видеокартами, попробую...
    3. Geforce 310M/512Мб. ОС Windows7, Core i3-330M, 2.17GHz...

  • 1. Какую версию CUDA вы используете?
    2. Вы переключали девайсы? Т.е. для каждого потока должен быть свой выделеный GPU, но не оба потока должны работать с одним GPU?
    3. Какое железо?

  • Потому что при случайном локальном доступе - дает.
    А при последовательном оптимальном для глобальной - отнимает.

  • Ну, конечно же! Спасибо.

  • Открыл ixbt, а там новость ZOTAC выпускает бесшумную 3D-карту GeForce GTS 450 ZONE Edition

    Цитата оттуда: Карта оснащена интерфейсами DVI, HDMI и DisplayPort. Цену изделия производитель не приводит.

  • Сколько блоков (нужны тысячи и более)?

    Не упираетесь ли вы в передачу данных по PCIe?

  • При использовании Driver API - все есть в драйвере.
    При использовании Runtime API - cudart.dll нужной битности.
    При использовании библиотек (cuBLAS, NPP и т.п.) - DLL-ки от них

  • Любая карта NVidia выпуска начиная с 2007 года т.е. серий 8xxx, 1xx, 2xx, 3xx, 4xx, 5xx.

    Разумный выбор - GT520, в ней есть все новые навороты и цена не кусается.

  • какая самая бюджетная карта с поддержкой cuda?

  • "но дело иногда доходит к абсурду, когда, скажем, вычисления для симуляции одного дня на фабрике занимают даже больше 24 часов при использовании однопоточной процессорной реализации"

    А не пробовали для начала на четыре-шесть потоков разделить? Современные CPU - многоядерные ж.

  • помогите пожалуйста, в общем у меня прога производит простое скалярное произведение векторов, и все работает, но если в код вставляю __syncthreads(); то он пишет идентификатор "syncthreads" не определен, при компиляции он его съедает почему то и считает правильно, но без syncthreads он тоже правильно считает, хотя теоретически если нити в блоке не одновременно досчитают, то будет ошибка. в общем помогите разобраться

  • Алексей, спасибо

  • Но вопросов этот простенький пример порождает много:

    - компиляция C-кода делается g++, хотя бы потому, что C & C++ образуют по-разному внешние имена для линковки:

    1. [olej@nvidia mobj]$ nm clock.o
    2. 00000000 T _Z12clock_cyclesv

    вот то _Z12... и есть типизация параметров и возврата C++.

    - стоит поменять g++ на gcc на линковке и всё рассыпается ... из-за дефаултных подключаемых библиотек (а как их дефаулт - посмотреть?):

    1. [olej@nvidia mobj]$ ldd multiple
    2.     linux-gate.so.1 =>  (0x0076b000)
    3.     libcudart.so.4 => /usr/local/cuda/lib/libcudart.so.4 (0x00ddc000)
    4.     libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x075d5000)
    5.     libm.so.6 => /lib/libm.so.6 (0x00b51000)
    6.     libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00b88000)
    7.     libc.so.6 => /lib/libc.so.6 (0x009a1000)
    8.     libdl.so.2 => /lib/libdl.so.2 (0x00b4a000)
    9.     libpthread.so.0 => /lib/libpthread.so.0 (0x00b2d000)
    10.     librt.so.1 => /lib/librt.so.1 (0x00b7d000)
    11.     /lib/ld-linux.so.2 (0x0097c000)

    - ну и в подтверждение того, что это одно и то же (почти) приложение:

    1.  
    2. [olej@nvidia mobj]$ ls -l *
    3. ...
    4. -rwxrwxr-x. 1 olej olej 11550 Ноя  5 21:09 multiple
    5. ...
    6. -rwxrwxr-x. 1 olej olej 11525 Ноя  5 21:09 solid
    7. ...
    8. [olej@nvidia mobj]$ ./multiple
    9. execution time was 184467452 cycles
    10. [olej@nvidia mobj]$ ./solid
    11. execution time was 132999604 cycles
    12. [olej@nvidia mobj]$ ./solid
    13. execution time was 160662372 cycles
    14. [olej@nvidia mobj]$ ./multiple
    15. execution time was 117963975 cycles

  • А теперь последняя (надеюсь) вставка - полная альтернатива предыдущему, но тот же clock.c компилируется отдельно, а multiple.cu отдельно, а объектные модули собираются в единое CUDA приложение (см. Makefile):

    1. #include <iostream>
    2. using namespace std;
    3. #include "clock.h"
    4.  
    5. // Kernel definition
    6. __global__ void VecAdd( void ) {
    7.     return;
    8. }
    9.  
    10. int main() {
    11.     int N = 100;
    12.     uint64_t t1, t2;
    13.     t1 = clock_cycles();
    14.     // Kernel invocation with N threads
    15.     VecAdd<<<1, N>>>();
    16.     t2 = clock_cycles();
    17.     cout << "execution time was " << ( t2 - t1 ) << " cycles" << endl;
    18. }

    Вы мне скажете: "а чем оно отличается"?
    А тем и отличается, 1-й строчкой #include, что код clock.c сюда не включается.

  • - файл solid.cu :

    1. #include <iostream>
    2. using namespace std;
    3. #include "clock.h"
    4.  
    5. #include "clock.c"  // реализация clock_cycles()
    6.  
    7. // Kernel definition
    8. __global__ void VecAdd( void ) {
    9.     return;
    10. }
    11.  
    12. int main() {
    13.     int N = 100;
    14.     uint64_t t1, t2;
    15.     t1 = clock_cycles();
    16.     // Kernel invocation with N threads
    17.     VecAdd<<<1, N>>>();
    18.     t2 = clock_cycles();
    19.     cout << "execution time was " << ( t2 - t1 ) << " cycles" << endl;
    20. }

    Он текстуально (по #include) включает файл C-кода (который должен компилироваться как C++ !) clock.c :
    1. #include "clock.h"
    2.  
    3. uint64_t clock_cycles( void ) {
    4.     uint64_t x;
    5.     asm volatile ( "rdtsc" : "=A" (x) );
    6.     return x;
    7. }

Copyright © 2008-2011 Alex Tutubalin