1-й в Украине сертификационный курс по UX от UXQB — крупнейшего в мире комьюнити UX специалистов
×Закрыть

GPGPU via C#: краткий обзор

Каждый год мы увеличиваем количество процессорных ядер, чтобы повысить общую производительность наших систем и улучшить пользовательский опыт. Восьмиядерным телефоном сегодня уже никого не удивишь. При этом нам доступен еще один вид вычислительных устройств, который большинство программистов обходит вниманием. Он имеет множество — сотни — вычислительных ядер. Это GPU, или графический процессор, который отвечает за прорисовку пользовательского интерфейса и обработку графики в играх.

С самого начала своего существования GPU был узкоспециализированным устройством, предназначенным только для преобразования и рендеринга переданных ему данных. При этом поток данных был только односторонним: от CPU к GPU. Однако с момента выхода Nvidia CUDA (Compute Unified Device Architecture) в 2007 году и OpenCL (Open Computing Language) в 2009, графические процессоры стали доступны для универсальных двунаправленных вычислений (так называемых вычислений общего назначения на графических процессорах или просто GPGPU).

С моей точки зрения, как .NET разработчика, получить доступ к огромной вычислительной мощности сотен ядер GPU было бы потрясающей возможностью, поэтому я попытался выяснить, каково нынешнее положение дел GPGPU на .NET Framework.

Что такое CUDA и OpenCL и в чем разница между ними

В целом это API, которые позволяют программисту выполнять определенный набор вычислений на GPU (или даже на таких экзотических устройствах, как FPGA). Это означает, что вместо отображения результата на дисплее, GPU определённым образом возвращает его клиентскому коду.

Между двумя этими технологиями есть существенные различия.

Во-первых, CUDA — это проприетарная система, разработанная и поддерживаемая только Nvidia, в то время как OpenCL — это скорее открытый стандарт, а не законченное решение или конкретная реализация. Поэтому CUDA доступен только на устройствах Nvidia, в то время как OpenCL может поддерживать любой производитель (кстати, чипы Nvidia также его поддерживают).

Во-вторых, CUDA — это технология, работающая только с графическим процессором (по крайней мере, в настоящее время), а интерфейс OpenCL может быть реализован различными устройствами (CPU, GPU, FPGA, ALU и т. д.).

Эти различия приводят к очевидным последствиям:

  • Производительность CUDA немного выше, чем OpenCL на чипах Nvidia.
  • Благодаря единому производителю (Nvidia), можно однозначно рассчитывать на соответствие документации и реализации CUDA, что не гарантируется для OpenCL.
  • OpenCL — это единственный вариант, если вам нужно работать с чем-либо, кроме чипов Nvidia.

Как это работает

Последовательность обработки данных с CUDA

Давайте опишем процесс работы с GPGPU при помощи схемы, представленной на рисунке:

  1. Формируем в ОЗУ данные, которые необходимо обработать.
  2. Копируем эти данные в видеопамять.
  3. Даём GPU задание обработать данные.
  4. GPU выполняет задачу параллельно на каждом ядре.
  5. Копируем результат обратно в ОЗУ.

Нужно отметить, что вычисления общего назначения на GPU имеют ряд ограничений:

  • Они не могут выполнять любые операции ввода-вывода.
  • Они не могут напрямую ссылаться на данные в памяти компьютера.

Несмотря на то, что общая схема кажется простой, модель вычислений и API вовсе не понятны интуитивно, особенно учитывая тот факт, что родной API доступен только на языках C и C++.

Мне кажется, это сильно препятствует распространению GPGPU.

GPGPU на платформе .NET

На платформе .NET пока что отсутствует встроенная поддержка GPGPU, поэтому нам придется полагаться на сторонние решения. При этом имеется не так уж много вариантов, из которых можно выбирать, поэтому давайте кратко рассмотрим доступные альтернативы среди активно разрабатываемых проектов. Характерно, что большинство из них основаны именно на Nvidia CUDA, а не OpenCL.

Alea GPU от QuantAlea

Alea GPU — это основанная на CUDA проприетарная библиотека с бесплатной и коммерческими версиями. Наличие даже бесплатной версии позволяет вам создавать коммерческое программное обеспечение, готовое к взаимодействию с GPU, для видеокарт потребительского уровня (серии Nvidia GeForce).

Документация очень хороша, приводятся примеры как на C#, так и на F#, а также предоставляются отличные сопровождающие графические схемы. Я бы сказал, что Alea GPU на данный момент является наиболее проработанным, задокументированным и простым в использовании решением.

Кроме того, библиотека кроссплатформенна и совместима с .NET Framework и Mono.

Hybridizer от Atimesh

Hybridizer — еще одна основанная на CUDA коммерческая библиотека, но её трудно сравнить с Alea GPU с точки зрения удобства использования. Во-первых, она бесплатная только для использования в образовательных целях (при этом все равно требует лицензию). Во-вторых, конфигурация крайне неудобна, поскольку требует создания проекта на C++, содержащего генерируемый библиотекой код, который при этом можно скомпилировать только в Visual Studio 2015.

ILGPU от Marcel Köster

ILGPU — это библиотека с открытым исходным кодом на основе CUDA, с хорошей документацией и примерами. Она не так абстрактна и проста в использовании, как Alea GPU, но тем не менее это впечатляющий и серьезный продукт, хотя он и разработан всего одним человеком. Библиотека совместима как с .NET Framework, так и с .NET Core.

Campy от Ken Domino

Campy — еще один интересный пример библиотеки с открытым исходным кодом, разработанной одним программистом. Пока что это ещё ранняя бета-версия, но она обещает максимально абстрактный API. Создана на .NET Core.

Я попробовал использовать в работе каждое из приведенных решений, но Hybridizer оказалось слишком неудобно конфигурировать, в то время как Campy просто не работал на моем оборудовании. Поэтому мы будет проводить оценивание с помощью библиотек Alea GPU и ILGPU.

Оценивание

Чтобы получить представление о GPGPU в .NET, мы реализуем простое приложение, которое преобразует набор изображений, применяя к ним простой фильтр.

Для сравнения создадим три реализации:

  1. С использованием стандартной Task Parallel Library из .NET Framework.
  2. С использованием Alea GPU.
  3. С использованием ILGPU.

Поскольку обе библиотеки используют CUDA, нам понадобится устройство Nvidia. К счастью, у меня такое имеется.

В общих чертах, мой компьютер имеет следующие характеристики:

  • CPU: Intel Core i5-4460 (4 cores no Hyper-Threading, 3.20 GHz base clock speed).
  • GPU: Nvidia Geforce GTX 1050 Ti (768 CUDA Cores, 4 GB GDDR5 VRAM, 1290 MHz Clock base clock speed).
  • RAM: 32 GB DDR3.
  • Накопитель: Samsung SSD 850 EVO 250 GB (что не так уж важно).
  • Операционная система: Windows 10 Pro.

Прежде чем продолжить, нам будет нужно установить CUDA Toolkit (нужно для ILGPU, но не для AleaGPU) с официального веб-сайта.

Обе эти библиотеки кроссплатформенны, но поскольку Alea GPU еще не адаптирована для .NET Core, мы создадим консольное приложение на базе Windows, используя последнюю версию .NET Framework, установленную на моем компьютере (а именно 4.7.1).

Нам понадобятся следующие Nuget-пакеты:

  • Install-Package Alea — Version 3.0.4
  • Install-Package FSharp.Core — Version 4.5.0
  • Install-Package ILGPU — Version 0.3.0
  • Install-Package SixLabors.ImageSharp — Version 1.0.0-beta0004

Alea GPU требует FSharp.Core, поскольку создана на его основе.

ImageSharp — это отличная кроссплатформенная библиотека обработки изображений, которая упростит нам процесс чтения и сохранения изображений.

Общий алгоритм

Наша программа будет довольно простой и состоит из следующих шагов:

  1. Загрузка изображения с помощью класса ImageSharp Image.
  2. Получение массива пикселей (представленного структурой Rgba32).
  3. Преобразование массива пикселей (инвертирование цветов).
  4. Перезагрузка их в объект Image.
  5. Сохранение результата в соответствующем каталоге.
Image<Rgba32> image = Image.Load(imagePath);
Rgba32[] pixelArray = new Rgba32[image.Height * image.Width];
image.SavePixelData(pixelArray);

string imageTitle = Path.GetFileName(imagePath);

Rgba32[] transformedPixels = transform(pixelArray);

Image<Rgba32> res = Image.LoadPixelData(
   config: Configuration.Default,
   data: transformedPixels,
   width: image.Width,
   height: image.Height);

res.Save(Path.Combine(outDir, $"{imageTitle}.{tech}.bmp"));

transform — это функция следующей сигнатуры: Func<Rgba32[], Rgba32[]>.

Мы сделаем реализацию этой функции отдельно для каждой выбранной технологии.

Реализация TPL

Task Parallel Library является стандартным и удобным способом работы с многопоточным кодом в .NET Framework. Приведенный ниже код реализует простой фильтр изображений и вряд ли требует комментариев. Должен отметить, что я изменяю массив пикселей, переданный методу Apply, чтобы получить лучшую производительность, хотя обычно я не одобряю такие функции.

public static class TplImageFilter
{
   public static Rgba32[] Apply(Rgba32[] pixelArray, Func<Rgba32, Rgba32> filter)
   {
      Parallel.For(0, pixelArray.Length, i => pixelArray[i] = filter(pixelArray[i]));

      return pixelArray;
   }

   public static Rgba32 Invert(Rgba32 color)
   {
      return new Rgba32(
         r: (byte)~color.R,
         g: (byte)~color.G,
         b: (byte)~color.B,
         a: (byte)~color.A);
   }
}

Реализация Alea GPU

Принимая во внимание приведенную ниже реализацию фильтра в Alea GPU, следует признать, что в коде нет существенной разницы с предыдущим примером на TPL. Единственное заметное отличие — это метод Invert, где нам пришлось использовать конструктор без параметров для структуры Rgba32, таково текущее ограничение кода, выполняемого Alea GPU.

public class AleaGpuImageFilter
{
   public static Rgba32[] Apply(Rgba32[] pixelArray, Func<Rgba32, Rgba32> filter)
   {
      Gpu gpu = Gpu.Default;

      gpu.For(0, pixelArray.Length, i => pixelArray[i] = filter(pixelArray[i]));

      return pixelArray;
    }

   public static Rgba32 Invert(Rgba32 from)
   {
      /* Noticeable that Alea GPU only support parameterless constructors */
      var to = new Rgba32
      {
         A = (byte)~from.A,
         R = (byte)~from.R,
         G = (byte)~from.G,
         B = (byte)~from.B
       };

       return to;
    }
}

Реализация ILGPU

По сравнению с предыдущими примерами, ILGPU API намного менее абстрактен. Во-первых, мы должны непосредственно выбирать целевое вычислительное устройство. Во-вторых, нам нужно явно загружать функцию ядра (kernel, чистая статическая функция), которая будет выполнятся ядрами GPU для преобразования наших данных. Функция ядра очень ограничена: она не может манипулировать ссылочными типами и, естественно, не может выполнять операции ввода-вывода. В-третьих, нам нужно явно выделить память в GPU RAM и загрузить в нее наши данные до запуска процесса преобразований.

public class IlGpuFilter : IDisposable
{
   private readonly Accelerator gpu;
   private readonly Action<Index, ArrayView<Rgba32>> kernel;

   public IlGpuFilter()
   {
      this.gpu = Accelerator.Create(
         new Context(),
         Accelerator.Accelerators.First(a => a.AcceleratorType == AcceleratorType.Cuda));
      this.kernel =
         this.gpu.LoadAutoGroupedStreamKernel<Index, ArrayView<Rgba32>>(ApplyKernel);
   }

   private static void ApplyKernel(
      Index index, /* The global thread index (1D in this case) */
      ArrayView<Rgba32> pixelArray /* A view to a chunk of memory (1D in this case)*/)
   {
      pixelArray[index] = Invert(pixelArray[index]);
   }

   public Rgba32[] Apply(Rgba32[] pixelArray, Func<Rgba32, Rgba32> filter)
   {
      using (MemoryBuffer<Rgba32> buffer = this.gpu.Allocate<Rgba32>(pixelArray.Length))
      {
         buffer.CopyFrom(pixelArray, 0, Index.Zero, pixelArray.Length);

         this.kernel(buffer.Length, buffer.View);

         // Wait for the kernel to finish...
         this.gpu.Synchronize();

         return buffer.GetAsArray();
       }
   }

   public static Rgba32 Invert(Rgba32 color)
   {
      return new Rgba32(
         r: (byte)~color.R,
         g: (byte)~color.G,
         b: (byte)~color.B,
         a: (byte)~color.A);
   }

   public void Dispose()
   {
      this.gpu?.Dispose();
   }
}

Простой тест на производительность

Наконец, нам нужно измерить скорость преобразований. Для этого я буду использовать стандартный класс Stopwatch:

var stopwatch = new Stopwatch();

foreach (string imagePath in imagePaths)
{
   /* Some Code */
   stopwatch.Start();
   Rgba32[] transformedPixels = transform(pixelArray);
   stopwatch.Stop();
   /* Some Code */
}

Console.WriteLine($"{tech}:\t\t{stopwatch.Elapsed}");

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

Для этого теста я использовал несколько фотографий в высоком разрешении, сделанных телескопом Hubble.

Пример преобразования

Прогнав программу на своем компьютере, я получил следующие усредненные результаты:

  • TPL: 0.737472333 секунд;
  • Alea GPU: 0.4567708 секунд;
  • ILGPU: 0.410849867 секунд.

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

Что из этого следует и стоит ли игра свеч?

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

С другой стороны, это уже хорошо, поскольку мы осуществили преобразования изображений заметно быстрее, а наш CPU при этом оставался свободным для выполнения другой работы!

Заключение

Вычисления общего назначения на GPU с использованием высокоуровневых языков вроде C# — это очень здорово, и я настоятельно рекомендую поиграться с такими библиотеками, как Alea GPU или ILGPU. Я искренне верю, что завтра многие из нас будут программировать в неоднородных вычислительных средах, состоящих из различных типов процессоров, и мы должны научиться использовать их возможности.

Я надеюсь, что встроенная поддержка GPGPU для .NET появится в недалеком будущем. Было бы здорово, если бы Microsoft сделала TPL, совместимым со стандартом OpenCL. Было бы также круто, если бы Microsoft приобрела Alea GPU, как она ранее сделала с Xamarin. Учитывая доступность Nvidia Tesla GPU в Azure это звучит вполне разумно.

Весь исходный код доступен на моем GitHub.

Комментарии и критика приветствуются. Возможно, вы укажете на мои ошибки в использовании API, и это поможет мне получить более значительный прирост в производительности.

LinkedIn

46 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Если запустить что-то сложнее чем invert то результат будет куда интересней. Хотя бы бикубическую интерполяцию.

Они не могут напрямую ссылаться на данные в памяти компьютера.

Это в корне неверное утверждение.

Спасибо за комментарий. Возможно вы правы, но тогда вам следует оставить ссылку в подтверждение сказанного. Моё же утверждение было основано на схеме которую я видел во многих источниках, а также на документации в Alea GPU: In a typical PC or compute cluster node, the memories of the CPU and GPU are physically distinct and connected by the PCI express bus. Data that is shared between the CPU and GPU must thus be allocated in both memories, and copied between them. Usually, this has to be done by the programmer, increasing the complexity of GPU programs.

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

Стоит просто открыть туториалы и их просмотреть. См. cudaMallocHost(), cudaHostAlloc().

а также на документации в Alea GPU:

С каких пор документация на недовраппер является первоисточником?

Моё же утверждение было основано на схеме которую я видел во многих источниках

А почему не на первоисточнике? У nVidia эта тема расжевана вдоль и поперёк!

Это появилось ещё во времена AGP (22 года назад) и с тех пор изменяется только обёртка.
devblogs.nvidia.com/...​e-data-transfers-cuda-cc

Позвольте, но те оптимизации о которых говорится в мануале:

As you can see in the figure, pinned memory is used as a staging area for transfers from the device to the host. We can avoid the cost of the transfer between pageable and pinned host arrays by directly allocating our host arrays in pinned memory.

И вот сопроводительная картинка

не отменяют того факта что вам нужно копировать данные из RAM в Video RAM, по этому, я думаю утверждение о том, что GPU не ссылается на RAM напрямую остаётся верным.

Вы ведь не можете отдать инструкцию именно GPU что бы оно пошло, посмотрело в RAM, и тем более, что бы оно туда записало что либо.

И вот тоже док с сайта nVidia , одно из указанных ограничений это: No CPU main memory access; no disk access .

не отменяют того факта что вам нужно копировать данные из RAM в Video RAM, по этому, я думаю утверждение о том, что GPU не ссылается на RAM напрямую остаётся верным.

В случае использование pinned (locked) memory функции копирования либо сбрасывают/инвалидируют кеш процессора либо вообще ничего не далает (WC режим).

Вы ведь не можете отдать инструкцию именно GPU что бы оно пошло, посмотрело в RAM, и тем более, что бы оно туда записало что либо.

Ещё как могу. Это столп всей архитектуры PC — прямой доступ к памяти (DMA). См. Bus Mastering.

И вот тоже док с сайта nVidia , одно из указанных ограничений это: No CPU main memory access; no disk access .

Там же указано, что это ограничение шейдерных языков, а не архитектуры GPU. Никто не запрещает хранить вертексы или текстуры в системной памяти. Оно к GPGPU не имеет никакого отношения.

Возможно мы неверно понимаем друг друга, когда я утверждал, что «вычисления общего назначения на GPU имеют ряд ограничений ... они не могут напрямую ссылаться на данные в памяти компьютера», я имел ввиду тот факт, что kernel функции которые непосредсвенно выполняются на GPU не могут прямо ссылатся и использовать память компьютера, и я продолжаю находить подтверждение этому.
Вот цитата из книги Professional CUDA C Programming (2014 года):

The following restrictions apply for all kernels:

  • Access to device memory only
  • ...
  • No support for function pointers

Отличная книжка, осталось только её прочитать. Стр 148 и дальше, pinned memory, zero copy memory, UVA.

Я не понимаю как упомянутые подходы к оптимизации преодолевают указанное ранее (этим же автором) ограничение. Как минимум, я думаю что считать моё утверждение «в корне не верным» всё же опроменчиво, тем более что оно упоминается многими авторами (в т.ч. в лекциях).
PS: Возможно Unified Memory позволяет обойти это ограничение, но это нужно отдельно исследовать

Я не понимаю как упомянутые подходы к оптимизации преодолевают указанное ранее (этим же автором) ограничение.

Тем, что можно расшарить любой кусок системной памяти между CPU и GPU. И обращаться к нему с обоих сторон. API всего лишь накладывают програмные ограничение по соображением безопасности, что расшарить можно память выделенную через API а не вообще любую. Так как GPU может вытащить кусок любой физической системной памяти себе для анализа.

Как минимум, я думаю что считать моё утверждение «в корне не верным» всё же опроменчиво, тем более что оно упоминается многими авторами (в т.ч. в лекциях).

Нет, оно по прежнему в корне неверно. Как показывает практика многие авторы не владеют всей информацией.

Они не могут напрямую ссылаться на данные в памяти компьютера.

В книге вполне доходчиво объяснён кейс с zero-copy, а это именно обращение к данным в памяти компьютера напрямую.

PS: Возможно Unified Memory позволяет обойти это ограничение, но это нужно отдельно исследовать

Unified Memory всего лишь создана для удобства, когда указатели на виртуальную память хоста и устройства совпадают.

Ніколи не розумів людей з айті, які крадуть книжки. Зарплатня наче дозволяє не займатися крадіжками і розповсюдженням вкраденого. Це в тебе релігія така?

Я не думаю что в мои личные обязянности входит фильтрация пирацкого контента вместо google. Я случайно нашёл эту книгу по ключевым словам и прикрепил на неё ссылку взяв её прямо из поиска. Кроме того данная цитата доступна и в google books, но прямая ссылка мне показалась удобнее.
Если ваша религия требует от вас заниматься копирастом и превентивно обвинять всех в воровстве, я вас прощаю.

Я случайно нашёл эту книгу по ключевым словам

Гугл адаптується під користувача. Це всі знають. То ж там нема нічого випадкового. Що то були за ключові слова, щоб замість nvidia, амазону, гуглокнижки, тощо, видало посилання на завантаження вкраденої книжки з файлобрухту?

копирастом

Це не він :)

Шаг первый: „cuda kernels” „restrictions” „functions”
Шаг второй: видишь фразу „CUDA KERNELS ARE FUNCTIONS WITH RESTRICTIONS”
Шаг третий: ищешь эту фразу „CUDA KERNELS ARE FUNCTIONS WITH RESTRICTIONS”

Майк, а напиши как-нибудь сюда общеобразовательную статейку по правильной работе с GPGPU?
Будешь в Минске, пивом проставлюсь.

Самоё тяжёлое это себя заставить :)

Так такое нужно в удовольствие делать. ;)

Что-то результаты совсем печальные ... Больше 0.1 сек на инвертацию картинка это уже безконечно долго. Иными словами затык во враперах . Думаю инвертация пикселей на CPU будет занимать менее 0.1 сек.
Для GPU это совсем не должно ничего занимать.

Что-то я быстро написал. Будет и того меньше. 0-1-2 кванта. То и есть 0-15(16)-31(32) милисекунд.

слишком мелкая задача для GPU

Да . Время старта будет больше чем полезных вычислений. Несоизмеримо больше !

Не время старта, а время пропихивания этих данных на карту и обратно.

В таком случае:
Alea GPU — ILGPU откуда разница в 40 милисекунд (8 на каждую картнику , так как было 8 bimap)?
TPL — вроде тоже ничего не грузит на GPU, откуда

0.737472333 секунд

?

ILGPU: 0.410849867

 — это все равно очень много . Если сделать через Directx\OpenGL время будет куда меньше . Время обработки в хуждем случае не должно прывышать 200 милисекунд на все 8 битмапки.

GPGPU у тебя стартует при включении компьютера.

Ну так-то да...
Я про вревя запуска ядра и время остановки. Запуск будет асинхронный, но стоять в очереди. CPU будет это ждать на синхронизации.
Функция ядра у ТС слишком простая чтобы реально занимать время.
Пропихивания данных тоже вряд ли является батлнэком. У автора GTX 1050 Ti которой bandwidth огромен ! За это время должны были быть прогружено гитары и даже чуток больше.

Напиши код на С и CUDA и померяй.

Это показатель кривизны ручек писателя.
А вообще на СPU эта операция зависит от скорости памяти и ручек писателя. Но если картинка маленькая, то уже от скорости кеша.

Прогнав программу на своем компьютере, я получил следующие усредненные результаты:

TPL: 0.737472333 секунд;
Alea GPU: 0.4567708 секунд;
ILGPU: 0.410849867 секунд.

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

Где тут 80%?
Вообще-то ускорение сильно зависит от собственно задачи. Время счета на GPU:это время загрузки данных в GPU, время счета там и время выгрузки. Учитывая эти 3 времени часто будет быстрее посчитать на CPU и не дергать GPU.
GPU же великолепен, когда время счета там прилично превышает время загрузки и выгрузки и алгоритм прекрасно параллелится по данным.

Если вы берёте время вычисления на СPU за 100%, то 0.41/0.74 * 100 (((

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

Привет. Спасибо за комментарий.
Под производительностью я понимаю отношение проделанной работы ко времени затраченной на её выполнение.
Тогда производительность для TPL = 1 / t-TPL, а производительность для ILGPU = 1 / t-ILGPU.
Относительный выигрыш в производительности будет разностью начального и конечного значений производительности выраженная в процентах изначального значения:
100 * (1/t-ILGPU — 1/t-TPL) / (1/TPL) % = 100 * (1/0.41 — 1/0.74) / (1/0.74) % = 80%

Eсли сократить ваше выражение, получим (t-TPL/t-ILGPU — 1) . Если это перевести в слова, будет «во сколько раз меньше картинок можно обработать на процессоре, чем на видюхе за единицу времени минус 1 раз». Как это вообще понимать? Нафига тут вычитать 1 раз?

Смотри, новое выражение, полученное в следствии преобразования (упрощения) исходного не обязано иметь более очевидный смысл чем исходное. Но в данном конкретном случае, я думаю можно считать, что 1 — это 100%, это исходная производительность, выраженная в процентах. В свою очередь t-TPL/t-ILGPU это новая производительность в процентах, соответственно их разница отображает на сколько процентов производительность изменилась

GPGPU via C#

О сравнение носорога с кактусом. Сейчас зачтем, кажется будет весело.

Было бы также круто, если бы Microsoft приобрела Alea GPU

Они еще от гитхаба не отошли, куда еще скупляться...

СUDA на C# - це збочення.

1. Додається сторонній прошарок зі своїми багами та обмеженнями (на відміну від користування рідного CUDA C++).
2. Сама мова C# не розрахована на ручне керування пам’яттю.
3. Як це все дебажити та профіліювати?
4. Всі приклади та документація від nvidia розраховані на С/С++.
5. Вгадайте, шо вам відповість nvidia, якщо ви скажете, що щось з CUDA не працює на C#?
6. Розмір ком’юніті: скільки питань на stackoverflow по CUDA на С/С++ і скільки на C#?

1. Додається сторонній прошарок зі своїми багами та обмеженнями (на відміну від користування рідного CUDA C++).

Єдине з чим погоджусь — так це стосовно обмежень.

2. Сама мова C# не розрахована на ручне керування
пам’яттю.

Не дуже й треба. Зараз кожен другий .Net прожект — використання анменейджмент коду з анменейджмент ліб, тай нічого — працюе.
Не бачу в цьму великої проблеми.

3. Як це все дебажити та профіліювати?

У тій ж віжуал студіі можна дебажити міксований код (С++/cli) якось і тут зроблять.

4. Всі приклади та документація від nvidia розраховані на С/С++.

Я так вважаю, якщо макрософт впряжеться той ліби для CUDA на .Net будуть и дебаггер и документація буде, не бачу дял цьго якихось принциповіх перешкод.

5. Вгадайте, шо вам відповість nvidia, якщо ви скажете, що щось з CUDA не працює на C#?

якщо вірно розподілити прошашки (.Net or CUDA side) то буде зрозуміло в кого за еррори питати.

6. Розмір ком’юніті: скільки питань на stackoverflow по CUDA на С/С++ і скільки на C#?

Питання не зовсім доречне, як майкрософт таки зробе таку лібу, то можна дивитись скільки людей її заюзають.

Якщо майкрософт впряжеться — то да, можна зробити все доволі круто. Але питання — навіщо це робити, якщо є С++?

Она не на C# - это просто враппер, биндинги к C#.

Ні, це не просто враппер. Треба ж компілювати С# код в проміжний код CUDA.

Сам пару лет назад игрался с AleaGPU для параллельных вычислений и у меня был прирост в раз 20 по скорости в некоторых случаях, так что всё зависит от выполняемых операций. Но всё круто если нужно просто сделать фазу map, а когда будет фаза reduce — сразу скорость ± одинаковая с cpu.

Microsoft сделала чуть иначе и сделала вычисления на cpu соизмеряемыми по скорости с c/c++ и с нимимальной нагрузкой на gc, развивая возможности simd вычислений в net — в том числе и для задач с графикой. Как результат имеем быстрые апишки в том числе и tpl для куда более широкого круга задач использующих cpu. Самое главное что для этого надо поминимуму писать unmanaged код

Подписаться на комментарии