代码之家  ›  专栏  ›  技术社区  ›  Maxter

将CPU并行。For转换为GPU GPU。For

  •  2
  • Maxter  · 技术社区  · 7 年前

    我创建了一个CPU并行程序。代码中的For循环如下:

    Vector2[] p;
    Vector2[] pnew;
    Vector2[] v;
    float[] m;
    
    Parallel.For(0, N, i =>
            {
                double dx;
                double dy;
                double invr;
                double invr3;
                double f;
                double ax;
                double ay;
                double eps = 0.02;
                ax = 0;
                ay = 0;
                for (int j = 0; j < N; j++)
                {
                    dx = p[j].X - p[i].X;
                    dy = p[j].Y - p[i].Y;
                    invr =1.0 / Math.Sqrt(dx * dx + dy * dy + eps);
                    invr3 = invr * invr * invr;
                    f = m[j] * m[i] * invr3;
                    ax += f * dx;
                    ay += f * dy;
                }
                pnew[i].X = (float)(p[i].X + dt * v[i].X + 0.5 * dt * dt * ax); /* save new position of particle "i" */
                pnew[i].Y = (float)(p[i].Y + dt * v[i].Y + 0.5 * dt * dt * ay);
                v[i].X += dt * (float)ax; /* update velocity of particle "i" */
                v[i].Y += dt * (float)ay;
            });
    

    我想做的是使用“Alea GPU”库将此代码转换为一个GPU For循环。所以我尝试了以下几点:

    Vector2[] p;
    Vector2[] pnew;
    Vector2[] v;
    float[] m;
    
        [GpuManaged]
        public void calculForceGPU()
        {
            Gpu.Default.For(0, N + 1, i =>
            {
                double dx;
                double dy;
                double invr;
                double invr3;
                double f;
                double ax;
                double ay;
                double eps = 0.02;
                ax = 0;
                ay = 0;
                for (int j = 0; j < N; j++)
                {
                    dx = p[j].X - p[i].X;
                    dy = p[j].Y - p[i].Y;
                    invr = 1.0 / Math.Sqrt(dx * dx + dy * dy + eps);
                    invr3 = invr * invr * invr;
                    f = m[j] * m[i] * invr3;
                    ax += f * dx;
                    ay += f * dy;
                }
                pnew[i].X = (float)(p[i].X + dt * v[i].X + 0.5 * dt * dt * ax); /* save new position of particle "i" */
                pnew[i].Y = (float)(p[i].Y + dt * v[i].Y + 0.5 * dt * dt * ay);
                v[i].X += dt * (float)ax; /* update velocity of particle "i" */
                v[i].Y += dt * (float)ay;
            });
        }
    

    i32 is not struct type.
    Source location stack:
    -> in C:\Users\...\Simulation.cs(628,21-628,42)
    -> at ....Simulation.[Void <calculForceGPU>b__36_0(Int32)]
    -> at Alea.Parallel.Device.DeviceFor.[Void Kernel(Int32, Int32, 
    System.Action`1[System.Int32])]
    -> at defining runtime32 (sm52,32bit)
    Loading method as kernel:
    -> Method: Alea.Parallel.Device.DeviceFor.[Void Kernel(Int32, Int32, 
    System.Action`1[System.Int32])]
    -> InstanceOpt: <None>
    -> Argument.#0: 0
    -> Argument.#1: 1025
    -> Argument.#2: System.Action`1[System.Int32]
    Getting or loading method as kernel:
    -> Method: Alea.Parallel.Device.DeviceFor.[Void Kernel(Int32, Int32, 
    System.Action`1[System.Int32])]
    -> InstanceOpt: <None>
    -> Argument.#0: 0
    -> Argument.#1: 1025
    -> Argument.#2: System.Action`1[System.Int32]
    

    我不知道如何解决这个错误。任何帮助都将不胜感激。

    更新

    所以问题可能是Vector2类型,因为它可能使用属性。所以我创建了自己的结构,它使用如下字段:

            struct Vector2Struct
        {
            public float X;
            public float Y;
    
            public  Vector2Struct(float x, float y)
            {
                X = x;
                Y = y;
            }
        }
    
        Vector2Struct[] p;
        Vector2Struct[] pnew;
        Vector2Struct[] v;
        float[] m;
    

    剩下的代码和以前差不多了。但我仍然得到相同的“i32不是结构类型”错误。

    如果放弃所有结构并改用浮点数组,则出现相同错误:

        float[] m;
        float[] pX;
        float[] pY;
        float[] pnewX;
        float[] pnewY;
        float[] vX;
        float[] vY;
    

    代码转储 根据评论。创建类的新实例应使其运行。你需要安装nuget ALEA和ALEA.FODY。我也认为你需要FSharp.Core来管理Alea

    using System;
    using Alea;
    using Alea.Parallel;
    
    namespace GalaxyTest
    {
    
    public class Simulation
    {
        // param
        object[] param;
    
        // masses      
        float[] m;
        float[] pX;
        float[] pY;
        float[] pnewX;
        float[] pnewY;
        float[] vX;
        float[] vY;
    
        // data
        static int N;
        double ratioPM;
        double ratioMasse;
        int Np;
        int Nm;
        int distribution;
        int simulType;
        float dt = 0.01F;
        double eps = 0.02;
        float Rrp = 1;
        float Rrm = 10;
    
        public Simulation()    //Constructor
        {
            Initializer();
            updatePointGPUAlea();
        }
    
        private void Initializer()
        {
            // Settings
            N = 1024;
            ratioPM = 0.25;
            ratioMasse = 1;
            Np = 256;
            Nm = 769;
            distribution = 0;
            simulType = 1;
    
            // vector Initialisation
            pX = new float[N];
            pY = new float[N];
            pnewX = new float[N];
            pnewY = new float[N];
            vX = new float[N];
            vY = new float[N];
            m = new float[N];
    
            // compute masses
            for (int i = 0; i < Np; i++)
            {
                m[i] = 1;
            }
            for (int i = Np; i < Nm; i++)
            {
                m[i] = -1 * (float)ratioMasse;
            }
    
            Random r = new Random();
            double R;
            double teta;
            double Rp;
            double Rn;
            float signe1, signe2, signe3, signe4;
    
            // Init pos = random shell
            for (int i = 0; i < N; i++)
            {
                Rp = 2.61;
                Rn = 45;
                teta = r.NextDouble() * 2 * Math.PI;
                signe1 = Math.Sign(r.NextDouble() - 0.5);
                signe2 = Math.Sign(r.NextDouble() - 0.5);
                signe3 = Math.Sign(r.NextDouble() - 0.5);
                signe4 = Math.Sign(r.NextDouble() - 0.5);
                if (m[i] > 0)
                {
                    pX[i] = (float)(Rp * Math.Cos(teta)) + 400 / 2;
                    pY[i] = (float)(Rp * Math.Sin(teta)) + 400 / 2;
                    vX[i] = (float)(r.NextDouble() * Rrp * signe1 + Math.Sqrt(Np) / 12 * 3 * Math.Sin(teta) * (0.4 - 1 / Math.Sqrt(10 + Rp)) * 3);
                    vY[i] = (float)(r.NextDouble() * Rrp * signe2 - Math.Sqrt(Np) / 12 * 3 * Math.Cos(teta) * (0.4 - 1 / Math.Sqrt(10 + Rp)) * 3);
    
                }
                else
                {
                    pX[i] = (float)(Rn * Math.Cos(teta)) + 400 / 2;
                    pY[i] = (float)(Rn * Math.Sin(teta)) + 400 / 2;
                    vX[i] = (float)r.NextDouble() * Rrm * signe3;
                    vY[i] = (float)r.NextDouble() * Rrm * signe4;
                }
            }
        }
    
        public void updatePointGPUAlea()
        {
            calculForceGPU();
            for (int i = 0; i < N; i++)
            {
                // Update de la position
                pX[i] = pnewX[i];
                pY[i] = pnewY[i];
            }
        }
    
        [GpuManaged]
        public void calculForceGPU()
        {
            Gpu.Default.For(0, N + 1, i =>
            {
                double dx;
                double dy;
                double invr;
                double invr3;
                double f;
                double ax;
                double ay;
                ax = 0;
                ay = 0;
                for (int j = 0; j < N; j++)
                {
                    dx = pX[j] - pX[i];
                    dy = pY[j] - pY[i];
                    invr = 1.0 / Math.Sqrt(dx * dx + dy * dy + eps);
                    invr3 = invr * invr * invr;
                    f = m[j] * m[i] * invr3;
                    ax += f * dx;
                    ay += f * dy;
                }
                pnewX[i] = (float)(pX[i] + dt * vX[i] + 0.5 * dt * dt * ax); /* save new position of particle "i" */
                pnewY[i] = (float)(pY[i] + dt * vY[i] + 0.5 * dt * dt * ay);
                vX[i] += dt * (float)ax; /* update velocity of particle "i" */
                vY[i] += dt * (float)ay;
    
            });
        }
    
    }
    
    }
    
    1 回复  |  直到 7 年前
        1
  •  5
  •   NineBerry    7 年前

    这可能是因为你用 X Y Vector2 结构类型。Alea不支持根据 documentation :

    另见 Alea: "i32 is not struct type

    推荐文章