Лучший способ сделать большое количество векторных вычислений с gpgpu?
У меня есть матрица 1 миллион столбцов х 1 миллион строк.
Мой алгоритм должен сделать:
Matrix m = Matrix(rows,cols)
for (colB: cols){
vector currColA = m.getcolumn(colA)
for (colB: cols){
vector currColB = m.getcolumn(colB)
result = currColA.dotProduct(colB)
return result;
}}
или вы могли бы также сказать:
Vectors [] v = Vectors[]
for (i: v.length){
vector v1 = v[i]
for (i: v.length){
vector v2 = v[i]
result = v1.dotProduct(v2)
return result;
}}
Мой вопрос: как правильно распределить память и инициализировать память для этой проблемы:
- Должен ли я выделить память для полной матрицы, инициализировать ее полной матрицей, а затем запустить алгоритм?
- или я должен выделить память для списка векторов, а затем перебрать этот список?
- или еще??
Меня беспокоит то, что я хотел бы свести к минимуму время передачи в GPU. Я попробовал подобные вычисления, модифицировав пример JCublas hello world для операции sgemm над 2 векторами, но при выполнении этого на моем большом числе векторов у меня было время передачи, удаляющее преимущества ускорения gpu.
Спасибо! PS: реализация может быть в любой библиотеке Java
1 ответ
Похоже, что вы применяете одноразовое ограничение. CPU->GPU-копирование, ожидание, вычисление, GPU->CPU-копирование, ожидание. Большинство людей не осознают неявных ожиданий, которые могут вызвать копии памяти.
Можете ли вы вести свою деятельность? Другими словами, ваш цикл состоит из следующего?
- CPU-> GPU copy
- Вычисление на GPU
- GPU->CPU copy
Чтобы выполнить это, вы должны использовать (например) 4 отдельные (по порядку) очереди команд, выполнять неблокирующую передачу для графического процессора в каждой очереди, выполнять выполнение ядра в каждой очереди и выдавать копию GPU-> CPU в каждой очередь, в таком порядке. Вы должны гарантировать, что оба буфера остаются действительными до ожидания (описано позже). Это позволит графическому процессору начать вычисления во время последующих передач памяти.
Кроме того, никогда не используйте блокировку передачи памяти, всегда используйте неблокирование. При каждом таком количестве (8?) Передач получите объект события для копии GPU-> CPU, но сначала дождитесь последнего объекта события, если это не первая итерация. Это ограничит ваши очереди и позволит вам повторно использовать буферы, но перекрывающиеся операции сохраняют пересылки и вычисления перекрывающимися. Мы ждем передачи 8 итераций назад, поэтому мы не истощаем очередь. Важно управлять глубиной очереди, чрезмерные рабочие элементы вызывают медленный GUI и голодание рабочих элементов.