@SergeySerge11

Откуда возникает ошибка при gpu вычислений при увеличении числа данных, в ILGPU Cuda ускорителе?

Unhandled exception. ILGPU.Runtime.Cuda.CudaException: an illegal memory access was encountered
Откуда возникает такая ошибка, в полностью. 100% рабочем коде, Н.а gpu. при CUDA акселераторе, при большом размере массива сортировки, только.

https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D1%82%D...
2-картинка. Реализация. Кстати вообще не могу найти не один пример нормальной многопоточной реализации этого алгоритма, особо не вникал, но почему у меня реализация прям абсолютно не похожа, при этом она точна по алгоритму. А что видел, там какие-то merge и рекурсии непонятные, аллокаций по миллиард раз, и нету многопоточности для приличия, и работает медленее). , А в англ вики вообще загадка тысячелетия что там, и где разделение на потоки.

Вот код, там в принципе вникать не нужно, там комментом помечено 2 интересные области. Я не понимаю как продебажить вообще.
Там нашел область где ошибка, если ее закоменить не ломается. Там простой swap элементов, судя по названию ошибки типа overflow индекс доступа к буферу, Но такого быть не может, там навесил проверок.
При этом на цпу все работает, при том что с simd реализовывал. А эта ломается ТОЛЬКО при большом масисве, где-то 20млн элементов. С видео памятью так же не может быть связано, так как закоменить ту строку все работает.
public  class SortGpu2:IDisposable
 { 
     private Accelerator accelerator;
     private Context context;
     public MemoryBuffer1D<int, Stride1D.Dense> arrBuffer;
     private Action<KernelConfig,Index2D,   ArrayView1D<int, Stride1D.Dense>> SortW0; 
     private Action<KernelConfig, Index2D,   ArrayView1D<int, Stride1D.Dense>> SortW;
     private ArrayView1D<int, Stride1D.Dense> view;
     public void Dispose()
     {
         arrBuffer.Dispose();
         context.Dispose();
         accelerator.Dispose();
     }

     public void SetData(int[] data)
     {
         arrBuffer.CopyFromCPU(data);
     }
     public void GetData(int[] data)
     {
         //accelerator.Synchronize();
         arrBuffer.CopyToCPU(data);
     }
     public SortGpu2(int count, Context context, Accelerator accelerator)
     {



         this.accelerator = accelerator;
         this.context = context;
         arrBuffer = accelerator.Allocate1D<int>(count);
         SortW0 = accelerator. LoadStreamKernel 
             <    Index2D,   ArrayView1D<int, Stride1D.Dense>>(SortKernelW0); 
         SortW = accelerator.LoadStreamKernel
             < Index2D,   ArrayView1D<int, Stride1D.Dense>>(SortKernelW);
         view = arrBuffer.View;
     }


     public void GpuSort()
     {
         Console.WriteLine("GPU SORT: Accelerator: " + accelerator);
         int nearPow2 = (int)BitOperations.RoundUpToPowerOf2((uint)arrBuffer.Length);
         int widthIndex = 0;
 
         
         for (int h = 2; h <= nearPow2; h <<= 1)
         {
             widthIndex++;
             for (int w = 0; w < widthIndex; w++)
             {

                 int numElemsInBlock = h >> w;
                 int numBlocksFull = (nearPow2 / numElemsInBlock);
                 int numGrid = (int)((numBlocksFull ) / accelerator.MaxNumThreadsPerGroup);
                 if (numGrid * accelerator.MaxNumThreadsPerGroup < numElemsInBlock)
                     numGrid++;
                 int numGroup= accelerator.MaxNumThreadsPerGroup;
                 if (w == 0)   //   начало каждого блока, с елочной перестановкой
                     SortW0(new KernelConfig(numGrid, numGroup),new Index2D(numBlocksFull, numElemsInBlock),   arrBuffer.View);
                 else    // все другие блоки с   линейными перестановками 
                     SortW(new KernelConfig(numGrid, numGroup), new Index2D(numBlocksFull, numElemsInBlock), arrBuffer.View);
// не связанный вопрос
// почему такая функция,  замедляет работу в миллиард раз( 
//  работает быстрее в 10 раз чем обычная сортировка, 
// а если поставить то работает на Log(N) дольше как и должно, так же как и на цпу в1 потоке),    при этом что 
//убрать ее, что поставить сортирует корректно, и не коррелирует с ошибкой вопроса
              //accelerator.Synchronize(); 

             }
         }
// и еще прикол, можно убрать внутри цикла, и поставить тут, и будет так же долго работатать,
// ни на наносекунду меньше, хотя та в массиве крутится, а это 1 раз вызывается. 
        // accelerator.Synchronize();
     }





     public static void SortKernelW0(Index2D index, ArrayView1D<int, Stride1D.Dense> arr)
     {
        // return;
         int indexBlock = Grid.GlobalIndex.X;// index.X;
         int numElemsInBlock = index.Y; 
         int begIndex = indexBlock * numElemsInBlock;
         int endIndex = begIndex + numElemsInBlock; 
         if (endIndex > arr.Length)
         {
             endIndex = begIndex + (numElemsInBlock >> 1);
             int offsetMain2 = numElemsInBlock - 1;
             for (int curIndex = begIndex; curIndex < endIndex; curIndex++)
             {
                 int nextIndex = curIndex + offsetMain2;
                 if (nextIndex >= arr.Length || curIndex >= arr.Length)
                 {
                     offsetMain2 -= 2;
                     continue;
                 }
                 if (arr[curIndex] > arr[nextIndex])
                     (arr[curIndex], arr[nextIndex])
                     = (arr[nextIndex], arr[curIndex]);
                 offsetMain2 -= 2;
             }
             return;
         }
         endIndex -= (numElemsInBlock >> 1);
         int offsetMain = numElemsInBlock - 1;
         for (int curIndex = begIndex; curIndex < endIndex; curIndex++)
         {
             int nextIndex = curIndex + offsetMain;

             if (arr[curIndex] > arr[nextIndex] 
/// ВОТ ЭТО ВСЕ НЕ СПАСАЕТ
&& curIndex < arr.IntLength 
&& nextIndex < arr.IntLength 
 && curIndex > 0 
&& nextIndex > 0)
/// ОШИБКА ТУТ Если закоменить эту строчку то работает.
                   (arr[curIndex], arr[nextIndex]) = (arr[nextIndex], arr[curIndex]);
                 offsetMain -= 2;
         } 

     }


     public static void SortKernelW(Index2D index,  ArrayView1D<int, Stride1D.Dense> arr)
     {
      
        // Interop.WriteLine("Hello WN: indexBlock {0}, numElemsBlock: {1}", index.X, index.Y);
         int indexBlock = Grid.GlobalIndex.X;// index.X;
         int numElemsInBlock = index.Y;
         int offsetMain = numElemsInBlock / 2;
         {
             int offset = indexBlock * numElemsInBlock;
             int endIndex = offset + numElemsInBlock;
             if (endIndex > arr.Length || offset >= arr.Length)
             {
                 endIndex = (int)arr.IntLength - (numElemsInBlock >> 1);
             }
             else
                 endIndex -= numElemsInBlock >> 1;
             for (int curIndex = offset; curIndex < endIndex; curIndex++)
             {

                 int nextIndex = curIndex + offsetMain;
                 if (arr[curIndex] > arr[nextIndex] )
                       (arr[curIndex], arr[nextIndex]) = (arr[nextIndex], arr[curIndex]);



             }

         }


     }
  
 }

p.s. есть где петиция против горизонтальных скролов.
  • Вопрос задан
  • 57 просмотров
Пригласить эксперта
Ваш ответ на вопрос

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

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