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. есть где петиция против горизонтальных скролов.