質問

I am trying to change my data structures from array of structures to structure of arrays and it seems I am writing lots of redundant code for it.(I want to keep both codes. As one is going to be run on GPU-Cuda and other on CPU)

for example I have

struct constant_node_AoS {
    int id;
    double Zmiddle;
    double Height;
    int Bstatus;
    double gamma;
    double e;
    double cc;
    double cs;
    double spv0;
    double spvp;
} nodes_constprop; //actually it is more like nodes_constprop[nNodes];

So what I did is: I created a new structure as

struct constant_node_struct_SoA {
    int *id;
    double *Zmiddle;
    double *Height;
    int *Bstatus;
    double *gamma;
    double *e;
    double *cc;
    double *cs;
    double *spv0;
    double *spvp;
}nodes_constprop_; 

then I have to have a code like these for memory allocation

nodes_constprop_.id =  new int[nNodes]
nodes_constprop_.Zmiddle =  new double[nNodes]
nodes_constprop_.Height=  new double[nNodes]
.
.
.

and a for loop to move data

for (int i=0;i<nNodes;i++){
   nodes_constprop_.id[i] =  nodes_constprop[i].id;
   nodes_constprop_.Zmiddle[i] =  nodes_constprop[i].Zmiddle;
   nodes_constprop_.Height[i] =  nodes_constprop[i].Height;
   .
   .
   .
}

and also another messy code for freeing data!

So I was wondering maybe with some macro tricks or I don't know some other clever idea bypass this mess?

For example have an array of pointers to structure's member pointers and their sizes then for loop into them and allocate them and move data around? Or some solution that can be scaled well, so if I add multiple other members it is automatically (or with minimal effort) taken care of?

For example is there a way to know how many members a struct have (at compile time - for example here it should be 10) so use it to know size of my pointers array?

Thanks

役に立ちましたか?

解決 4

Well my answer to my question :D

I used subscript operator overloading.

struct constant_node_AoS {
    union {int id;double id_double;}
    double Zmiddle;
    double Height;
    union {int Bstatus;double Bstatus_double;}
    double gamma;
    double e;
    double cc;
    double cs;
    double spv0;
    double spvp;
    double &operator[](int i){
    switch (i){
      case 0:
        return id_double;
      case 1:
        return Zmiddle;
      case 2:
        return Height;
      case 3:
        return Bstatus_double;
      case 4:
        return gamma;
      case 5:
        return e;
      case 6:
        return cc;
      case 7:
        return cs;
      case 8:
        return spv0;
      case 9:
        return spvp;
    }

} nodes_constprop[nNodes];

and also similar for other structure!

struct constant_node_struct_SoA {
    union {long long *id;double *id_double}
    double *Zmiddle;
    double *Height;
    union {long long *Bstatus;double *Bstatus_double}
    double *gamma;
    double *e;
    double *cc;
    double *cs;
    double *spv0;
    double *spvp;
    double* &operator[](int i){
    switch (i){
      case 0:
        return id_double;
      case 1:
        return Zmiddle;
      case 2:
        return Height;
      case 3:
        return Bstatus_double;
      case 4:
        return gamma;
      case 5:
        return e;
      case 6:
        return cc;
      case 7:
        return cs;
      case 8:
        return spv0;
      case 9:
        return spvp;
    }
}nodes_constprop_;

so now I can easily have this

for (int i=0;i<10;i++)
    g_.nodes_constprop_[i] = new double[nNodes];

for (int i=0;i<nNodes;i++)
    for (int j=0;j<10;j++)
        (g_.nodes_constprop_[j])[i] = (g_tmp->nodes_constprop[i])[j];

The reason I added union was I couldnt figure out type casting errors without it (although I should anyway added __align(8) to it. Also the reason for long long was also whatever I did, pointer operations on int was 4 bytes. I added following code

typedef int int_align_double __attribute__ ((aligned(sizeof(double))));
typedef int_align_double* pint_align_double;

but still variables of type pint_align_double, were 4 byte pointers. So I changed it to long long so I can get 8 byte pointer alignment.

他のヒント

A macro trick looks like this. In file struct.def put

NODE( int, id )
NODE( double, Zmiddle )
NODE( double, Height )
NODE( int, Bstatus )
NODE( double, gamma )
NODE( double, e )
NODE( double, cc )
NODE( double, cs )
NODE( double, spv0 )
NODE( double, spvp )

In file struct.h put

#ifdef NODE_AOS
struct constant_node_AoS {
#define NODE(a,b) a b ;
#include "struct.def"
} nodes_constprop[ nNodes ];

#define NODE_ID(i) nodes_constprop[ (i) ].id 
#define NODE_HEIGHT(i) nodes_constprop[ (i) ].Height
// repeat for rest of fields
#endif

#ifdef NODE_SOA
#define NODE(a,b) a nodes_ ## b[ nNodes ]  ;
#include "struct.def"

#define NODE_ID(i) nodes_id[ (i) ]
#define NODE_HEIGHT(i) nodes_Height[ (i) ]
// repeat for rest of fields
#endif

Your code uses NODE_ID(i) to access id.

My suggestion would be to create couple of functions: one to translate an array of struct to the struct of arrays and another to do the opposite.

For illustration, let me simplify the structs to:

struct constant_node_AoS {
    int id;
    double Zmiddle;
};

and

struct constant_node_struct_SoA {
    int *id;
    double *Zmiddle;
};

The first function would be:

constant_node_struct_SoA translatetoSoA(constant_node_AoS* array, size_t size)
{
   constant_node_struct_SoA soa;
   soa.id = new int[size];
   soa.Zmiddle = new double[size];
   for ( size_t i = 0; i < size; ++i )
   {
      soa.id[i] = array[i].id;
      soa.Zmiddle[i] = array[i].Zmiddle;
   }

   return soa;
}

The second function would be:

constant_node_AoS* translateToAoS(constant_node_struct_SoA soa, size_t size)
{
   constant_node_AoS* array = new constant_node_AoS[size];
   for (size_t i = 0; i < size; ++i )
   {
      arra[i].id = soa.id[i];
      array[i].Zmiddle = soa.Zmiddle[i];
   }

   return array;
}

Since your structure member names are the same, you can use @brian's example to define the nodes, and then use a macro to access the nodes

#ifdef PROPS_AOS
#define PROPNAME(var, name) (var).name
#else
#define PROPNAME(var, name) *(var).name
#endif
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top