2017-02-16 30 views
1

Это может быть просто проблема с тем, что объекты памяти, выделенные платформой .NET, не были правильно выровнены по страницам, но я не могу посмотрите, почему нулевая копия для меня медленнее, чем ненулевая копия.«Нулевая копия» медленнее в моей программе OpenCL/Cloo (C#), чем ненулевая копия

В этот вопрос включится код inline, но полный источник можно посмотреть здесь: https://github.com/kwende/ClooMatrixMultiply/blob/master/GiantMatrixOnGPU/GPUMatrixMultiplier.cs.

Поскольку это моя первая попытка получить нуль-копию, я написал простой пример умножения матрицы. Сначала я инициализирую свои объекты OpenCL:

private void Initialize() 
    { 
     // get the intel integrated GPU 
     _integratedIntelGPUPlatform = ComputePlatform.Platforms.Where(n => n.Name.Contains("Intel")).First(); 

     // create the compute context. 
     _context = new ComputeContext(
      ComputeDeviceTypes.Gpu, // use the gpu 
      new ComputeContextPropertyList(_integratedIntelGPUPlatform), // use the intel openCL platform 
      null, 
      IntPtr.Zero); 

     // the command queue is the, well, queue of commands sent to the "device" (GPU) 
     _commandQueue = new ComputeCommandQueue(
      _context, // the compute context 
      _context.Devices[0], // first device matching the context specifications 
      ComputeCommandQueueFlags.None); // no special flags 

     string kernelSource = null; 
     using (StreamReader sr = new StreamReader("kernel.cl")) 
     { 
      kernelSource = sr.ReadToEnd(); 
     } 

     // create the "program" 
     _program = new ComputeProgram(_context, new string[] { kernelSource }); 

     // compile. 
     _program.Build(null, null, null, IntPtr.Zero); 
     _kernel = _program.CreateKernel("ComputeMatrix"); 
    } 

... это выполняется только один раз, если мой код не был инициализирован. Затем я попадаю в основной корпус. Для ненулевой копии, я делаю следующее:

public float[] MultiplyMatrices(float[] matrix1, float[] matrix2, 
    int matrix1Height, int matrix1WidthMatrix2Height, int matrix2Width) 
    { 
     if (!_initialized) 
     { 
      Initialize(); 
      _initialized = true; 
     } 

     ComputeBuffer<float> matrix1Buffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, 
      matrix1); 
     _kernel.SetMemoryArgument(0, matrix1Buffer); 

     ComputeBuffer<float> matrix2Buffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, 
      matrix2); 
     _kernel.SetMemoryArgument(1, matrix2Buffer); 

     float[] ret = new float[matrix1Height * matrix2Width]; 
     ComputeBuffer<float> retBuffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadWrite | ComputeMemoryFlags.CopyHostPointer, 
      ret); 
     _kernel.SetMemoryArgument(2, retBuffer); 

     _kernel.SetValueArgument<int>(3, matrix1WidthMatrix2Height); 
     _kernel.SetValueArgument<int>(4, matrix2Width); 

     _commandQueue.Execute(_kernel, 
      new long[] { 0 }, 
      new long[] { matrix2Width, matrix1Height }, 
      null, null); 

     unsafe 
     { 
      fixed (float* retPtr = ret) 
      { 
       _commandQueue.Read(retBuffer, 
        false, 0, 
        ret.Length, 
        new IntPtr(retPtr), 
        null); 

       _commandQueue.Finish(); 
      } 
     } 

     matrix1Buffer.Dispose(); 
     matrix2Buffer.Dispose(); 
     retBuffer.Dispose(); 

     return ret; 
    } 

Вы можете увидеть, как я явно устанавливая CopyHostPointer для всех моих распределений ComputeBuffer. Это отлично.

Я тогда сделайте следующее корректировку (который включает в себя установку «UseHostPointer» и призывающую Карта/Unmap вместо Read):

public float[] MultiplyMatricesZeroCopy(float[] matrix1, float[] matrix2, 
     int matrix1Height, int matrix1WidthMatrix2Height, int matrix2Width) 
    { 
     if (!_initialized) 
     { 
      Initialize(); 
      _initialized = true; 
     } 

     ComputeBuffer<float> matrix1Buffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, 
      matrix1); 
     _kernel.SetMemoryArgument(0, matrix1Buffer); 

     ComputeBuffer<float> matrix2Buffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, 
      matrix2); 
     _kernel.SetMemoryArgument(1, matrix2Buffer); 

     float[] ret = new float[matrix1Height * matrix2Width]; 
     ComputeBuffer<float> retBuffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadWrite | ComputeMemoryFlags.UseHostPointer, 
      ret); 
     _kernel.SetMemoryArgument(2, retBuffer); 

     _kernel.SetValueArgument<int>(3, matrix1WidthMatrix2Height); 
     _kernel.SetValueArgument<int>(4, matrix2Width); 

     _commandQueue.Execute(_kernel, 
      new long[] { 0 }, 
      new long[] { matrix2Width, matrix1Height }, 
      null, null); 

     IntPtr retPtr = _commandQueue.Map(
      retBuffer, 
      false, 
      ComputeMemoryMappingFlags.Read, 
      0, 
      ret.Length, null); 

     _commandQueue.Unmap(retBuffer, ref retPtr, null); 
     _commandQueue.Finish(); 

     matrix1Buffer.Dispose(); 
     matrix2Buffer.Dispose(); 
     retBuffer.Dispose(); 

     return ret; 
    } 

Время говорит все это, однако. Моя программа плюет это:

CPU Умножение матриц: 1178.5ms

GPU матричного умножения (копия): 115.1ms

GPU Матрица умножения (ноль копия): 174.1ms

GPU (ш/copy) на 10.23892x быстрее.

GPU (без копий) - 6.769098x быстрее.

... так что нулевая копия медленнее.

+0

что было имя устройства? –

+0

имя: Intel (R) OpenCL версия: OpenCL 2.0 –

+0

Я имею в виду имя gpu, номер поколения, ... –

ответ

2

Благодаря huseyin tugrul buyukisik мне удалось выяснить, что происходит.

Мне нужно было обновить драйверы Intel. Как только я это сделал, нулевая копия была намного быстрее.

Ради потомства, вот окончательный вариант кода нулевой копии:

public float[] MultiplyMatricesZeroCopy(float[] matrix1, float[] matrix2, 
     int matrix1Height, int matrix1WidthMatrix2Height, int matrix2Width) 
    { 
     if (!_initialized) 
     { 
      Initialize(); 
      _initialized = true; 
     } 

     ComputeBuffer<float> matrix1Buffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, 
      matrix1); 
     _kernel.SetMemoryArgument(0, matrix1Buffer); 

     ComputeBuffer<float> matrix2Buffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, 
      matrix2); 
     _kernel.SetMemoryArgument(1, matrix2Buffer); 

     float[] ret = new float[matrix1Height * matrix2Width]; 
     GCHandle handle = GCHandle.Alloc(ret, GCHandleType.Pinned); 
     ComputeBuffer<float> retBuffer = new ComputeBuffer<float>(_context, 
      ComputeMemoryFlags.UseHostPointer, 
      ret); 
     _kernel.SetMemoryArgument(2, retBuffer); 

     _kernel.SetValueArgument<int>(3, matrix1WidthMatrix2Height); 
     _kernel.SetValueArgument<int>(4, matrix2Width); 

     _commandQueue.Execute(_kernel, 
      new long[] { 0 }, 
      new long[] { matrix2Width, matrix1Height }, 
      null, null); 

     IntPtr retPtr = _commandQueue.Map(
      retBuffer, 
      true, 
      ComputeMemoryMappingFlags.Read, 
      0, 
      ret.Length, null); 

     _commandQueue.Unmap(retBuffer, ref retPtr, null); 
     //_commandQueue.Finish(); 

     matrix1Buffer.Dispose(); 
     matrix2Buffer.Dispose(); 
     retBuffer.Dispose(); 
     handle.Free(); 

     return ret; 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^