Почему у Nvidia Pascal есть ядра FP32 и FP64? Почему я не могу использовать их одновременно?
Я пытаюсь понять архитектуру графического процессора Nvidia, но я немного застрял на чем-то, что кажется довольно простым. Каждый потоковый мультипроцессор в Pascal состоит из ядер 64xFP32 и 32xFP64. И вот мои два вопроса:
- Почему Nvidia поместила в чип модули FP32 и FP64? Почему бы просто не поставить модули FP64, способные выполнять 2xFP32 операции на одну инструкцию (например, наборы команд SIMD в CPU).
- Почему я не могу использовать все модули FP32 и FP64 одновременно?
Я думаю, что оба являются решениями по проектированию аппаратного обеспечения, но я хотел бы знать больше деталей об этой теме. Любая информация по этому поводу более чем приветствуется!
EDIT1:
- Если можно выполнять FP32 и FP64 одновременно, означает ли это, что графический процессор с 8TFLOPS SP и 4TFLOPS DP может дать (теоретически) 12 TFLOPS смешанных TFLOPS?
- В случае CUDA, как это достигается? Я просто использую double и float одновременно в моем ядре? Или мне нужно передать какой-то флаг в NVCC?
1 ответ
Почему Nvidia поместила в чип модули FP32 и FP64?
Я думаю о проникновении на рынок, чтобы продать как можно больше. Без FP64 ребята, занимающиеся научными исследованиями, не могут даже попробовать демонстрацию научно важного программного обеспечения gpgpu, которое использует FP64(и даже игры могут использовать некоторую двойную точность в некоторых случаях). Без FP32 физика игры и симуляции были бы очень медленными, или GPU потребовал бы ядерного реактора. Без FP16 нет быстрой нейронной сети. Если бы был только FP32, симуляция нейронной сети работала бы с половинной скоростью, иначе суммирование FP64 не сработало бы.
Кто знает, может быть, в будущем появятся выделенные ядра FP_raytrace, которые делают трассировку ультрабыстрым, так что больше не будет мучительных обновлений DX12 DX11 DX9 и улучшенной графики.
В конечном счете, я бы не сказал "нет" для GPU на основе FPGA, который может преобразовать некоторые ядра из FP64 в FP32 или некоторые специальные функциональные ядра для приложения, затем преобразовать все в FP64 для другого приложения и даже преобразовать все в одно толстое ядро, которое выполняет последовательную работу (например, компиляция шейдеров). Это было бы полезно для людей, делающих много разных вещей на компьютере. Например, мне может понадобиться больше умножений, чем дополнений, и FPGA может помочь здесь. Но теперь деньги говорят и говорят "фиксированная функция на данный момент", и лучший доход достигается за счет комбинации FP64 и FP32 (и FP16 в последнее время).
Почему бы просто не поставить модули FP64, способные выполнять 2xFP32 операции на одну инструкцию (например, наборы команд SIMD в CPU).
SIMD ожидает всегда одну и ту же операцию для нескольких данных и меньше удовольствия для скалярных ядер GPGPU. ТАКЖЕ для изготовления 2xFP32 из FP64 потребуется больше транзисторов, чем для чистого FP64, больше тепла, может быть больше задержки.
Чем больше транзисторов, тем больше вероятность сбоя в работе, поэтому более вероятно, что 1024 FP32 GPU будет произведено, чем 512 FP64_furable GPU.
Почему я не могу использовать все модули FP32 и FP64 одновременно?
Вычисления со смешанной точностью могут быть выполнены в cuda и opencl, так что вы можете получить еще быстрее, используя все ядра, но применимо только в ситуациях, не связанных с нехваткой памяти, что редко и трудно кодировать.
Ответ на редактирование 1:
вот подробный источник http://www.nvidia.com/content/PDF/sc_2010/CUDA_Tutorial/SC10_Accelerating_GPU_Computation_Through_Mixed-Precision_Methods.pdf
Короче говоря, они не добавляют, что есть "убывающая отдача", которая почему-то не позволяет масштабировать%100 на всех ядрах из-за необходимых "дополнительных циклов" между вычислениями с различной точностью. Когда они не смешаны, им нужны "дополнительные итерации" между блоками, которые также не позволяют масштабировать%100. Кажется, это более полезно, поскольку ускорение "FP64" вместо "FP32" вниз (но наличие множества ядер FP64 должно быть выгодно (для повышения FP32), вы можете протестировать их с чем-то вроде ядра nbody (которое не является узким местом в памяти)). FP64 занимает очень много памяти (и строк кэша (и локальной памяти)), поэтому я предложил nbody алгоритм, который повторно использует некоторые данные для N(>64k, например) раз. Мой GPU имеет мощность 1/24 FP64, поэтому я не доверяю своему компьютеру. У тебя есть титан? Вы должны попробовать, может быть, он имеет на 50% больше энергии, чем его значение рекламных GFLOP (но значение TDP рекламы может ограничивать его частоту и может таять)
Этот источник: http://www.nvidia.com/content/nvision2008/tech_presentations/NVIDIA_Research_Summit/NVISION08-Mixed_Precision_Methods_on_GPUs.pdf
говорит "выдающаяся производительность и точность", но я не мог найти физический решатель для игр, использующих FP32 + FP32(усеченный FP64), возможно, его деньги говорят снова, если кто-то сделает это, это будет "выдающаяся производительность и крушение" в играх.(может быть, хуже, чем Furmark взрывающаяся Gpus)
люди даже используют целые числа (произведение целочисленных точек) поверх чисел здесь: https://devblogs.nvidia.com/parallelforall/mixed-precision-programming-cuda-8/
В случае CUDA, как это достигается? Я просто использую double и float одновременно в моем ядре? Или мне нужно передать какой-то флаг в NVCC?
Пример итеративного уточнения с использованием fp64+fp32 в той же функции:
https://www.sciencesmaths-paris.fr/upload/Contenu/HM2012/07-dongarra_part2.pdf
страницы 26-28.
Для части opencl здесь amd evergreen(серия hd5000), способный выдавать 1dp fma + 1 sp(или 1 sf) каждый цикл.
http://www.microway.com/download/whitepaper/gpgpu_architecture_and_performance_comparison_2010.pdf
Я протестирую что-то вроде nbody на своем R7-240, который будет 1/24 или 1/26-й степени fp32 как fp64 завтра.
Редактировать: это работает.
__kernel void sumGPU(__global float * a,__global float * b)
{
int idx = get_global_id(0);
float a0=a[idx];
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
//a0=convert_float(convert_double(a0)+2.0);
//a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
a0+=2.0f;
b[idx] = a0;
}
он переключается между 13,02 и 12,85 мс, когда отключен только один из комментариев.
Примечание: ядра сами по себе не являются fp32. Там нет ядер. Существуют планировщики, связывающие аппаратные ресурсы (fp32,fp64,special_function,registers) с инструкциями ядра потоков. Темы тоже не настоящие темы. Поэтому, когда вы используете fp32, затем fp64, затем fp32, затем fp64_square_root, он зарезервирует необходимые ресурсы, когда они понадобятся. Когда нет, они являются опциями для других рабочих элементов (но один рабочий элемент не может использовать более 1-2 fp32 ALU, которые я подозреваю (IDK, я сделал это))
Изменить (2018/03): Есть FP_raytrace
(второй абзац этого ответа выше) становится реальностью?
(NVIDIA) https://www.geforce.com/whats-new/articles/nvidia-rtx-real-time-game-ray-tracing
Или это еще один маркетинговый трюк? Если у него есть аппаратная сторона, тогда люди Raytracer могут работать быстрее, но это не помогло бы мобильному геймеру или симулятору физики без трассировки лучей. Зачем мне платить больше за эти трассировщики лучей, если я собираюсь редактировать некоторые видео? Может быть, они тоже могут быть сегментированы как другие, но, возможно, за большие деньги.