Russian Qt Forum
Ноябрь 22, 2024, 04:49 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Не масштабится :-(  (Прочитано 13987 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Март 05, 2021, 13:42 »

Добрый день

Тормозит здесь

Код
C++ (Qt)
std::vector<Vec3> CPolySDS::CalcVerNormals( const std::vector<Vec3> & pos ) const
{
std::vector<Vec3> dst(pos.size());
 
for (size_t i = 0; i < mNorIndex.size(); i += mNumVerPerFace) {
Vec3 faceN = GetFaceNormal(&mNorIndex[i], mNumVerPerFace, pos);
for (size_t j = 0; j < mNumVerPerFace; ++j)
dst[mNorIndex[i + j]] += faceN;
}
 
// ну и далее вектор посылается на видеокарту
 
Отладчик показывает что 58% съедается на цикле. Скорость 1 fps, т.е. мышей можно елозить с большим трудом. Если отключаю цикл - скорость 6 fps, тоже не блеск, но лучше. Число итераций цикла > 2 лимонов.

Ну разумеется стандартное решение (OpenMP) здесь ничего не ускоряет, а Qt-шный "конкурент" даже замедляет. Это даже без локера что нужен для вложенного цикла. Оно и понятно - слишком мала "нагрузка" (или "кластер"), в GetFaceNormal по сути только вычитание векторов + векторное произведение.

Конечно первая мысль - увеличить кластер. Типа: да, GetFaceNormal слишком мал, но итераций-то прилично, за 2 мульена. Вот давайте "объединим" и 4 ядрам дадим 4 задачи по 500К итераций каждая - и будет счастье  Улыбающийся Проверял много раз (и в данном случае), хотя знал что OpenMP делает это  по умолчанию. Ну конечно никакого счастья не получил, скорость та же.

Др варианты. Самое крутое - перенести на GPU, но это такой головняк из-за жалких 5 строчек кода  Плачущий  Искать еще какую-то "систему" (давеча видел какой-то "open"), ну это долго а рез-т не гарантируется.

Как же все-таки бороться с этим маленьким говнецом?

Спасибо


Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #1 : Март 05, 2021, 22:22 »

Я так подозреваю, что такая задержка в функции
Код
C++ (Qt)
GetFaceNormal(&mNorIndex[i], mNumVerPerFace, pos)
 
А что будет с fps, если цикл оставить, а на эту функцию заглушку поставить?

Ну типа
Код
C++ (Qt)
Vec3 GetFaceNormal(...)
{
return Vec3();
}
 
« Последнее редактирование: Март 05, 2021, 22:28 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
vipet
Бывалый
*****
Offline Offline

Сообщений: 452


Просмотр профиля
« Ответ #2 : Март 06, 2021, 04:55 »


Др варианты. Самое крутое - перенести на GPU, но это такой головняк из-за жалких 5 строчек кода  Плачущий  Искать еще какую-то "систему" (давеча видел какой-то "open"), ну это долго а рез-т не гарантируется.

Как же все-таки бороться с этим маленьким говнецом?

Спасибо



GPU без "головняка":
https://thrust.github.io/
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Март 06, 2021, 11:15 »

А что будет с fps, если цикл оставить, а на эту функцию заглушку поставить?
Не понял задумку, нагрузка мала, а мы делаем ее еще меньше. Ну ладно, проверить нетрудно. Получил 2 fps (вместо 1), что впрочем не значит "вдвое" (там просто округление до целого). Что естественно - расчетов стало меньше. Но никакого намека на ускорение на 4 ядрах. Совсем. Что будет на большем числе ядер - хз (нередко возникает обратный эффект)

Да, и вот момент: для вложенного цикла  нужен локер, оператор += разумеется not thread-safe. Как его реализовать? Ясно нужен unfair но боюсь что и его здесь не хватит.

Что делает этот код: вычисляет нормали к вертексам как сумму нормалей всех фейсов (полигонов) ссылающихся на данный вертекс. Конфликты (data race) здесь редки, но увы, они есть

GPU без "головняка":
https://thrust.github.io/
Ну сначала надо установить и "осмотреть" не такой уж маленький софт. Образующуяся "еще одна зависимость" также не радует. Конечно это нормально, но не сказал бы что "так уж просто"  Улыбающийся Бегло глянув примеры, я понял следующее: если я имею (массивные) вектора на CPU - мне надо передать их на GPU. Боюсь что уже эта операция займет куда больше времени чем простецкий расчет в главной нитке. Поэтому вряд ли удастся "ускорить это (конкретное) место". Вот если бы изначально все данные планировались на thrust - тогда .. может быть..

Буду рад продолжить обсуждение деталей GPU реализации, хотя знаю здесь очень мало.  Но уверен ответа не последует, "тыцалки" (или "тыцуны"?) почему-то никогда не хотят говорить о "тыцаемом"  Улыбающийся

« Последнее редактирование: Март 06, 2021, 11:17 от Igors » Записан
tux
Global Moderator
Бывалый
*****
Offline Offline

Сообщений: 404



Просмотр профиля
« Ответ #4 : Март 06, 2021, 15:21 »

Но уверен ответа не последует, "тыцалки" (или "тыцуны"?) почему-то никогда не хотят говорить о "тыцаемом"  Улыбающийся
При таком отношении к местному населениию, вы точно ответа не получите. Даже, если кто-то и умеет читать мысли.
Записан

Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Март 07, 2021, 07:38 »

При таком отношении к местному населениию,
Нормальное отношение, если нет желания (или познаний) просто обсудить предмет - то зачем предлагать его другим?

вы точно ответа не получите.
Если я хочу "что-то получить" - я гуглю, а на форуме я хочу поговорить с умными  людьми  Улыбающийся
Записан
tux
Global Moderator
Бывалый
*****
Offline Offline

Сообщений: 404



Просмотр профиля
« Ответ #6 : Март 07, 2021, 12:15 »

Если я хочу "что-то получить" - я гуглю, а на форуме я хочу поговорить с умными  людьми  Улыбающийся
А о чём тут можно говорить вообще? Вы выдали некоторый кусок кода, который на первый взгляд вполне нормальный. Ускорить его можно разве что "разворачиванием" цикла. Насколько хорош остальной код, можно только догадываться.
Возможно, что вы просто сделали/выбрали плохую архитектуру проекта. Соответственно, никто ничего особо сказать и не может. Ни "тыцуны", ни обычные программисты.
Если бы у меня возникла такая проблема, я бы просто сделал минимальный проект с проблемным кодом и выложил бы его. И, вот тут, уже можно было бы о чём то рассуждать.
Записан

Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Март 08, 2021, 09:37 »

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

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

Возможно, что вы просто сделали/выбрали плохую архитектуру проекта.
Дежурная прибаутка про "корявую архитектуру". Если мы хотим рисовать объекты, нормали к вертексам иметь/считать обязаны. Это момент чисто технический, к "архитектуре" отношения не имеет.

А о чём тут можно говорить вообще?
 
О многом. Напр я ожидал чего-то типа "надо смотреть в сторону GPU" (как обычно изрекают знатоки). Но как туда смотреть? OpenGL? Ну на скромном core 3.3 (требования) - это вряд ли. Значит что-то типа OpenCL, CUDA (кстати тыцнутый thrust в нее входит) и.т.п. Никогда этим не занимался и энтузиазма лезть в это огромное болота никакого. Но "жизнь заставит", данный случай в принципе типовой. Почему бы и не "попробывать"?

Как видно из кода, нужна простейшая вещь - работать по индексу Улыбающийся  Ну или читать-писать эл-ты массивов. Но где это взять - хз
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #8 : Март 08, 2021, 17:23 »

Обязательно ли посылать полный вектор dst на видеокарту?
Может разделить по ядрам и каждое ядро сформирует и отправит свой кусок вектора?
Ещё неплохо было бы подумать насчёт оптимизации количества итераций?
По опыту, могу сказать, что программная оптимизация не даёт вау-эффекта, а оптимизация на уровне бизнес логики может в десятки тысяч раз ускорить.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Март 09, 2021, 10:15 »

Обязательно ли посылать полный вектор dst на видеокарту?
Может разделить по ядрам и каждое ядро сформирует и отправит свой кусок вектора?
Кстати для этого надо расшарить контекст для каждой нитки (недавно за это получил). Что будет - не знаю, проверить не просто. В любом случае "передача данных на GPU" - всего лишь одна из проблем. Если делать на GLSL - придется изрядно попыхтеть уже с чтением эл-тов массива. С записью - намного больше. А с локом - вообще не знаю как, наверно придется сделать 2 прохода чтобы от него избавиться. Конечно написать пару-тройку шейдеров, аккуратно все зарядить, и.т.п., в общем - кал ужасный.

Ещё неплохо было бы подумать насчёт оптимизации количества итераций?
По опыту, могу сказать, что программная оптимизация не даёт вау-эффекта, а оптимизация на уровне бизнес логики может в десятки тысяч раз ускорить.
Конечно эта рекомендация справедлива, но увы - не всегда возможна/применима.  А главное - почти всегда "дорогостоящая". Из-за буквально 5 строк мы начинаем "большую войну" или "глубокий анализ" (который может ни к чему и не привести). Такой путь явно "не технологичен".

Смотрим на исходный код: простые расчеты, большая кратность - явно работа для той скотины с огромными мощностями но мозгами курчонка. Да, "brute force" - это нехорошо, но все очень довольны когда она есть  Улыбающийся
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #10 : Март 09, 2021, 11:12 »

Я имел ввиду не шарить один вектор на 4 потока/ядра, а каждый поток делает свой локальный вектор, и его посылает на GPU, или куда там еще.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Март 09, 2021, 12:04 »

Я имел ввиду не шарить один вектор на 4 потока/ядра, а каждый поток делает свой локальный вектор, и его посылает на GPU, или куда там еще.
Шарить надо контекст, просто так посылать из др нитки (не главной где контекст создан) = отлуп/ошибка. Ну и шансов на ускорение немного, ведь N ниток льют "в одну дырочку". Вообще мне кажется неверным пытаться в данном случае что-то делать "руками", здесь явно нужна "современная технология" (о которых так любят говорить Улыбающийся )
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #12 : Март 09, 2021, 13:51 »

Я имел ввиду не шарить один вектор на 4 потока/ядра, а каждый поток делает свой локальный вектор, и его посылает на GPU, или куда там еще.
Шарить надо контекст, просто так посылать из др нитки (не главной где контекст создан) = отлуп/ошибка. Ну и шансов на ускорение немного, ведь N ниток льют "в одну дырочку". Вообще мне кажется неверным пытаться в данном случае что-то делать "руками", здесь явно нужна "современная технология" (о которых так любят говорить Улыбающийся )
Затык, я так понимаю в расчетах, а не в "дырочке".

Код:
std::vector<Vec3> CPolySDS::CalcVerNormals( const std::vector<Vec3> & pos, size_t startIndx, size_t endIndx) const
{
std::vector<Vec3> dst(pos.size());
 
for (size_t i = startIndx; i < endIndx; i += mNumVerPerFace)
......
}

// На каждом ядре запустить
CalcVerNormals(pos, 0, mNorIndex.size() / 4);
CalcVerNormals(pos, (mNorIndex.size() / 4) + 1 , (mNorIndex.size() / 4) * 2);
// и т.д.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Март 10, 2021, 08:43 »

// На каждом ядре запустить
Да делал это много раз, и руками и тулзами - ни фига не ускоряет, а может и замедляет. См. стартовый пост. Повторюсь: ситуевина типовая, слишком мелкие задачи не масштабятся

Затык, я так понимаю в расчетах, а не в "дырочке".
Я понял что Вы предлагаете параллельную передачу данных на GPU, а там уже считать. Такая передача вряд ли будет быстрее т.к. буфер один. И это только передача

Да, а что же со ссылочкой выше? Ну как всегда - тыцнуло и смылoсь Плачущий
Записан
RedDog
Частый гость
***
Offline Offline

Сообщений: 221


Просмотр профиля
« Ответ #14 : Март 10, 2021, 11:37 »

Код:
58% съедается на цикле.
Я и предлагаю этот цикл распаралеллить на все 4 ядра. Каждое посчитает свою 1/4 итераций. При 4-х ядрах не в 4 конечно, но раза в 2 как минимум должен быть прирост.
И после окончания потоков слить полученные 4 результата в один вектор, который и запулить на ГПУ.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.111 секунд. Запросов: 22.