@SergeySerge11

Почему gpu вычисления ILGPU медленнее в 10 раз чем CPU?

Единственная походу библиотека, которая хоть разок смогла скомпилироваться, ILGPU, с хорошей документацией, правда мало.
Но почему все работает в 10-100, 1000 раз медленнее. И вообще смотрю диспетчер не нагружает видеокарту.
https://ilgpu.net/docs/02-beginner/03-kernels-and-...
Ну вот например вот этот код закидываю, main меняю на параметризированную функцию, и
сравниваю с нативным arr[i]=arr2[i];
Результат CPU быстрее в 320 раз, и это типа главный пример. Я думал видеокарта долдна быть в миллиард раз быстрее. А не в 320!!! раз медленнее, пользуйтесь в проектах.

|GPUTest | Single[1000000] | Single[1000000] | 300,582.2 us | 469,759.0 us | 25,749.07 us |
| Native | Single[1000000] | Single[1000000] | 856.1 us | 191.9 us | 10.52 us

В чем проблема, во всех библиотеках get started код типа такого.
И видеокарту не грузит, хотя иногда грузит, ни чего не меняя. 0% в диспетчере.

[ArgumentsSource(nameof(Agruments))]
 [Benchmark]
 public void GPUTest(float[] input, float[]output)
 {
     // Initialize ILGPU.
     Context context = Context.CreateDefault();
     Accelerator accelerator = context.CreateCLAccelerator(1);//context.GetPreferredDevice(preferCPU: false)  .CreateAccelerator(context);

     // Load the data.
     using  MemoryBuffer1D<float, Stride1D.Dense> deviceData = accelerator.Allocate1D(input);
     using MemoryBuffer1D<float, Stride1D.Dense> deviceOutput = accelerator.Allocate1D<float>(output);

     // load / precompile the kernel
     Action<Index1D, ArrayView<float>, ArrayView<float>> loadedKernel =
         accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<float>, ArrayView<float>>(Kernel);


     // finish compiling and tell the accelerator to start computing the kernel
         loadedKernel((int)deviceOutput.Length, deviceData.View, deviceOutput.View);
         accelerator.Synchronize();

     // wait for the accelerator to be finished with whatever it's doing
     // in this case it just waits for the kernel to finish.
     

     // moved output data from the GPU to the CPU for output to console
     float[] hostOutput = deviceOutput.GetAsArray1D();

     output = hostOutput;

     accelerator.Dispose();
     context.Dispose();
 }

Там еще в примере почему-то не освобождается MemoryBuffer который наследует IDisposable
  • Вопрос задан
  • 150 просмотров
Решения вопроса 1
AshBlade
@AshBlade Куратор тега C#
Просто хочу быть счастливым
Вот из-за этого:
// Initialize ILGPU.
     Context context = Context.CreateDefault();
     Accelerator accelerator = context.CreateCLAccelerator(1);//context.GetPreferredDevice(preferCPU: false)  .CreateAccelerator(context);

     // Load the data.
     using  MemoryBuffer1D<float, Stride1D.Dense> deviceData = accelerator.Allocate1D(input);
     using MemoryBuffer1D<float, Stride1D.Dense> deviceOutput = accelerator.Allocate1D<float>(output);

     // load / precompile the kernel
     Action<Index1D, ArrayView<float>, ArrayView<float>> loadedKernel =
         accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<float>, ArrayView<float>>(Kernel);


     // finish compiling and tell the accelerator to start computing the kernel
         loadedKernel((int)deviceOutput.Length, deviceData.View, deviceOutput.View);
         accelerator.Synchronize();


Объяснение: ты в каждом тесте постоянно создаешь новые объекты, которые необходимы для работы фреймворка. Это должно быть тяжелые объекты (много содержат, тяжело инициализируются).
Вынеси их инициализацию из-вне метода в какой нибудь Setup метод. Раз уж ты пользуешься BenchmarkDotNet, то вот помощь с этим

UPD: оптимизировал бенчмарк - теперь GPU быстрее
public class SampleBenchmark
{
    static void Kernel(Index1D i, ArrayView<float> data, ArrayView<float> output)
    {
        output[i] = data[i % data.Length];
    }
    public static IEnumerable<object[]> Arguments => new[] {new object[]{new float[1000000], new float[1000000]} };
    private float[] _outputBuffer = new float[1000000];
    private float[] _inputBuffer = new float[1000000];
    
    private Context? _context;
    private Accelerator? _accelerator;
    private Action<Index1D, ArrayView<float>, ArrayView<float>>? _loadedKernel;
    private MemoryBuffer1D<float, Stride1D.Dense>? _deviceData;
    private MemoryBuffer1D<float, Stride1D.Dense>? _deviceOutput;
    
    [GlobalSetup]
    public void Setup()
    {
        var random = new Random();
        for (var i = 0; i < _inputBuffer.Length; i++)
        {
            _inputBuffer[i] = random.NextSingle();
        }
        
        _context = Context.CreateDefault();
        _accelerator = _context.GetPreferredDevice(preferCPU: false).CreateAccelerator(_context);
        _loadedKernel = _accelerator!.LoadAutoGroupedStreamKernel<Index1D, ArrayView<float>, ArrayView<float>>(Kernel);
        _deviceData = _accelerator!.Allocate1D(_inputBuffer);
        _deviceOutput = _accelerator!.Allocate1D(_outputBuffer);
    }

    [GlobalCleanup]
    public void TearDown()
    {
        _context?.Dispose();
        _accelerator?.Dispose();
        _deviceData?.Dispose();
        _deviceOutput?.Dispose();
    }
    [ArgumentsSource(nameof(Arguments))]
    [Benchmark]
    public void GPUTest(float[] input, float[] output)
    {
        // finish compiling and tell the accelerator to start computing the kernel
        _loadedKernel!((int)_deviceOutput.Length, _deviceData.View, _deviceOutput.View);
        _accelerator!.Synchronize();
    }

    [Benchmark]
    [ArgumentsSource(nameof(Arguments))]
    public void CpuTest(float[] input, float[] output)
    {
        for (var i = 0; i < input.Length; i++)
        {
            output[i] = input[i];
        }
    } 
}


| Method  | input           | output          | Mean      | Error    | StdDev   |
|-------- |---------------- |---------------- |----------:|---------:|---------:|
| GPUTest | Single[1000000] | Single[1000000] |  61.18 us | 0.101 us | 0.095 us |
| CpuTest | Single[1000000] | Single[1000000] | 243.54 us | 3.114 us | 2.600 us |
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы