Передача массива внутри структуры в CUDAfy

Используя VS 2012, .NET 4.5, 64bit и CUDAfy 1.12, у меня есть следующее подтверждение концепции

using System;
using System.Runtime.InteropServices;
using Cudafy;
using Cudafy.Host;
using Cudafy.Translator;

namespace Test
{
[Cudafy(eCudafyType.Struct)]
[StructLayout(LayoutKind.Sequential)]
public struct ChildStruct
{
    [MarshalAs(UnmanagedType.LPArray)]
    public float[] FArray;
    public long FArrayLength;
}

[Cudafy(eCudafyType.Struct)]
[StructLayout(LayoutKind.Sequential)]
public struct ParentStruct
{
    public ChildStruct Child;
}

public class Program
{
    [Cudafy]
    public static void KernelFunction(GThread gThread, ParentStruct parent)
    {
        long length = parent.Child.FArrayLength;
    }

    public static void Main(string[] args)
    {
        var module = CudafyTranslator.Cudafy(
          ePlatform.x64, eArchitecture.sm_35,
          new[] {typeof(ChildStruct), typeof(ParentStruct), typeof(Program)});
        var dev = CudafyHost.GetDevice();
        dev.LoadModule(module);

        float[] hostFloat = new float[10];
        for (int i = 0; i < hostFloat.Length; i++) { hostFloat[i] = i; }

        ParentStruct parent = new ParentStruct
        {
            Child = new ChildStruct
            {
                FArray = dev.Allocate(hostFloat),
                FArrayLength = hostFloat.Length
            }
        };

        dev.Launch(1, 1, KernelFunction, parent);

        Console.ReadLine();
    }
}
}

Когда программа запускается, я получаю следующую ошибку на dev.Launch:

Type 'Test.ParentStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.

Если я удаляю массив float из ChildStruct, он работает как положено.

Работая в C/C++/Cli и CUDA C в прошлом, я осознаю природу ошибки. Некоторые решения этой ошибки предлагают установить размер структуры вручную, используя Size параметр MarshalAs, но это невозможно из-за разнообразия типов в структуре.

Я посмотрел на сгенерированный файл.cu, и он генерирует массив с плавающей точкой в ​​виде float * что я и ожидал.

Есть ли способ передать массив в структуре в ядро? И если нет, что является лучшим вторым вариантом? Эта проблема не существует в CUDA C и существует только потому, что мы выполняем маршалинг из CLR.

2 ответа

Решение

Я потратил много времени на чтение исходного кода CUDAfy, чтобы посмотреть, есть ли решение этой проблемы.

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

Невозможность отправки массива с плавающей точкой в ​​структуре является ограничителем показа. Я закончил тем, что сделал PInvoke для CUDA Runtime и не использовал CUDAfy.

Это ограничение.NET, а не CUDAfy. Данные должны быть кратковременными, а массив нефиксированного размера - нет. Это верно и основано на модульных тестах CUDAfy на codeplex:

[Cudafy]
[StructLayout(LayoutKind.Sequential, Size=64, CharSet = CharSet.Unicode)]
public unsafe struct PrimitiveStruct
{
    public fixed sbyte Message[32];
    public fixed char MessageChars[16];
}

Также нет причин для явного хранения длины массива, поскольку вы можете использовать свойство Length в коде устройства.

Другие вопросы по тегам