0

つまり、アンマネージ C++ 乗算関数を使用して C# から SIMD 演算を実行し、ポインターをいじろうとしています。

C++ 関数:

extern "C" __declspec(dllexport) void SIMDVector4Mult( __m128* a, __m128* b )
{
    __m128 c = _mm_mul_ps( *a, *b );
    memcpy( &(a->m128_f32), &(c.m128_f32), sizeof( a->m128_f32 ) );
}

C# SIMDVector4 構造体:

[StructLayout( LayoutKind.Sequential, Size = 16 )]
struct SIMDVector4
{
    float x;
    float y;
    float z;
    float w;


    public SIMDVector4( float x, float y, float z, float w )
    {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
    }


    public override string ToString( )
    {
        return "X: " + x + ", Y: " + y + ", Z: " + z + ", W: " + w;
    }


    public static unsafe SIMDVector4 operator *( SIMDVector4 a, SIMDVector4 b )
    {
        SIMDVector4Mult( ref a, ref b );
        return a;
    }


    [DllImport("SIMDMathLibrary.dll", CallingConvention = CallingConvention.Cdecl )]
    extern private static unsafe void SIMDVector4Mult( ref SIMDVector4 a, ref SIMDVector4 b );
}

その目的は、私の C# コード ベースに SIMD 演算を追加することと、P/Invoke を使って C# と C++ を組み合わせて練習することです。

それらを float* 変数として受け取り、それらを一時的な __m128 変数に memcpy し、乗算を行ってから memcpy すると機能します。しかし、それは C# で各変数を単独で乗算するよりも遅くなります。最適化された Vector4 クラスを使用してこれをテストしました。これは、copy-multiply-copy 方式の約 10 倍のパフォーマンスを実現します。

タイトルに記載されている保護されたメモリの読み取り/書き込みアクセスエラーに遭遇する現在のセットアップを含む、ほぼ十数の異なることを試しました:「保護されたメモリを読み書きしようとしました。これは多くの場合、他のメモリが破損していることを示しています."

このエラーを修正するにはどうすればよいですか? このエラーを修正する必要がありますか? 意図を完全に達成する別の方法を試す必要がありますか?

ありがとう。

4

1 に答える 1

2

これは、動作するはずの更新されたものです。現在、構造体はアラインされた ptr をラップしているため、追加の 4 ~ 8 バイトが必要です。間接化によるパフォーマンス ヒットが不明です。VirtualAlloc は一度に束を整列させるため、一度に大きなチャンクを割り当てます。

以下の例は非常にずさんです。可能であれば、代わりに CLI/C++ を使用することも検討してください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;


namespace ConsoleApplication1
{
    class Program
    {
        unsafe static void Main(string[] args)
        {
            using (AlignedBlock block = new AlignedBlock(SIMDVector4.Sizeof, AlignedBlock.AllocationGranularity / SIMDVector4.Sizeof))
            {
                for (int index = 0; index < block.Count; index++)
                {
                    SIMDVector4.Create(block[index], 1, 2, 3, 4);
                }

                SIMDVector4 a = SIMDVector4.Create(block[0], 1, 2, 3, 4);
                SIMDVector4 b = SIMDVector4.Create(block[1], 1, 2, 3, 4);
                SIMDVector4 c = SIMDVector4.Create(block[2], 5, 6, 7, 8);
                SIMDVector4 d = a * b * c;
                Console.WriteLine(d.ToString());
            }

            Console.ReadLine();
        }
    }

    public sealed unsafe class AlignedBlock : CriticalFinalizerObject, IDisposable
    {
        private void* ptr;

        static AlignedBlock()
        {
            SYSTEM_INFO info = new SYSTEM_INFO();
            NativeMethods.GetSystemInfo(ref info);
            PageSize = (int)info.dwPageSize;
            AllocationGranularity = (int)info.dwAllocationGranularity;
        }

        public AlignedBlock(int itemSize, int count)
        {
            this.ItemSize = itemSize; 
            this.Count = count;
            ptr = NativeMethods.VirtualAlloc(IntPtr.Zero, new UIntPtr((uint)this.ByteSize), AllocationType.COMMIT, MemoryProtection.READWRITE).ToPointer();
        }


        ~AlignedBlock()
        {
            this.Dispose();
        }

        public static int PageSize { get; private set; }
        public static int AllocationGranularity { get; private set; }
        public int ItemSize { get; private set; }
        public int Count { get; private set; }
        public int ByteSize
        {
            get
            {
                return this.Count * this.ItemSize;
            }
        }

        public void* this[int index]
        {
            get
            {
                int offset = this.ItemSize * index;
                return ((byte*) this.ptr) + offset;
            }
        }

        public void Dispose()
        {
            bool result = NativeMethods.VirtualFree(new IntPtr(this.ptr), new UIntPtr(0), 0x8000);
            this.ptr = null;
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    unsafe struct SIMDVector4
    {
        public const int Sizeof = 16;
        private float* ptr;

        public static SIMDVector4 Create(void* ptr, float x, float y, float z, float w)
        {
            float* value = (float*)ptr;

            SIMDVector4 vector = new SIMDVector4(value);
            *value = x;
            value++;
            *value = y;
            value++;
            *value = z;
            value++;
            *value = w;
            value++;
            return vector;
        }

        private SIMDVector4(float* ptr)
        {
            this.ptr = ptr;
        }

        public bool IsEmpty
        {
            get
            {
                return this.ptr == null;
            }
        }
        public float x
        {
            get
            {
                if (this.IsEmpty)
                {
                    return 0f;
                }

                return *(ptr);
            }

            set
            {
                if (!this.IsEmpty)
                {
                    *(this.ptr) = value;
                }
            }

        }
        public float y
        {
            get
            {
                if (this.IsEmpty)
                {
                    return 0f;
                }

                return *(ptr + 1);
            }

            set
            {
                if (!this.IsEmpty)
                {
                    *(this.ptr + 1) = value;
                }
            }

        }
        public float z
        {
            get
            {
                if (this.IsEmpty)
                {
                    return 0f;
                }

                return *(ptr + 2);
            }

            set
            {
                if (!this.IsEmpty)
                {
                    *(this.ptr + 2) = value;
                }
            }

        }
        public float w
        {
            get
            {
                if (this.IsEmpty)
                {
                    return 0f;
                }

                return *(ptr + 3);
            }

            set
            {
                if (!this.IsEmpty)
                {
                    *(this.ptr + 3) = value;
                }
            }
        }

        public override string ToString()
        {
            return "X: " + x + ", Y: " + y + ", Z: " + z + ", W: " + w;
        }


        public static SIMDVector4 operator *(SIMDVector4 a, SIMDVector4 b)
        {

            SIMDVector4Mult(a.ptr, b.ptr);
            return new SIMDVector4(a.ptr);
        }

        [DllImport(@"C:\Users\xxx\Documents\Visual Studio 2010\Projects\TestDll\Debug\TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
        extern private static unsafe void SIMDVector4Mult(void* a, void* b);
    }

    internal static class NativeMethods
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize,
               uint dwFreeType);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize,
               AllocationType flAllocationType, MemoryProtection flProtect);

        [DllImport("kernel32.dll")]
        public static extern void GetSystemInfo([MarshalAs(UnmanagedType.Struct)] ref SYSTEM_INFO lpSystemInfo);

    }


    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEM_INFO
    {
        internal _PROCESSOR_INFO_UNION uProcessorInfo;
        public uint dwPageSize;
        public IntPtr lpMinimumApplicationAddress;
        public IntPtr lpMaximumApplicationAddress;
        public IntPtr dwActiveProcessorMask;
        public uint dwNumberOfProcessors;
        public uint dwProcessorType;
        public uint dwAllocationGranularity;
        public ushort dwProcessorLevel;
        public ushort dwProcessorRevision;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct _PROCESSOR_INFO_UNION
    {
        [FieldOffset(0)]
        internal uint dwOemId;
        [FieldOffset(0)]
        internal ushort wProcessorArchitecture;
        [FieldOffset(2)]
        internal ushort wReserved;
    }

    [Flags()]
    public enum AllocationType : uint
    {
        COMMIT = 0x1000,
        RESERVE = 0x2000,
        RESET = 0x80000,
        LARGE_PAGES = 0x20000000,
        PHYSICAL = 0x400000,
        TOP_DOWN = 0x100000,
        WRITE_WATCH = 0x200000
    }

    [Flags()]
    public enum MemoryProtection : uint
    {
        EXECUTE = 0x10,
        EXECUTE_READ = 0x20,
        EXECUTE_READWRITE = 0x40,
        EXECUTE_WRITECOPY = 0x80,
        NOACCESS = 0x01,
        READONLY = 0x02,
        READWRITE = 0x04,
        WRITECOPY = 0x08,
        GUARD_Modifierflag = 0x100,
        NOCACHE_Modifierflag = 0x200,
        WRITECOMBINE_Modifierflag = 0x400
    }
}   
于 2012-10-26T01:36:24.517 に答える