Subsections

3.4 PUP Framework

3.4.1 How does one write a pup for a dynamically allocated 2-dimensional array?

The usual way: pup the size(s), allocate the array if unpacking, and then pup all the elements.

For example, if you have a 2D grid like this:

class foo {
 private:
  int wid,ht;
  double **grid;
  ...other data members

  //Utility allocation/deallocation routines
  void allocateGrid(void) {
    grid=new double*[ht];
    for (int y=0;y<ht;y++)
      grid[y]=new double[wid];
  }
  void freeGrid(void) {
    for (int y=0;y<ht;y++)
      delete[] grid[y];
    delete[] grid;
    grid=NULL;
  }

 public:
  //Regular constructor
  foo() {
    ...set wid, ht...
    allocateGrid();
  }
  //Migration constructor
  foo(CkMigrateMessage *) {}
  //Destructor
  ~foo() {
    freeGrid();
  }

  //pup method
  virtual void pup(PUP::er &p) {
    p(wid); p(ht);
    if (p.isUnpacking()) {
      //Now that we know wid and ht, allocate grid
      allocateGrid(wid,ht);
    }
    //Pup grid values element-by-element
    for (int y=0;y<ht;y++)
      for (int x=0; x<wid; x++)
        p|grid[y][x];
    ...pup other data members...
  }
};

3.4.2 When using automatic allocation via PUP::able, what do these calls mean? PUPable_def(parent); PUPable_def(child);

For the automatic allocation described in Automatic allocation via PUP::able of the manual, each class needs four things:

See charm/tests/charm++/megatest/marshall.[hC] for an executable example.

3.4.3 What is the difference between p|data; and p(data);? Which one should I use?

For most system- and user-defined structure someHandle, you want p|someHandle; instead of p(someHandle);

The reason for the two incompatible syntax varieties is that the bar operator can be overloaded outside pup.h (just like the std::ostream's operator<<); while the parenthesis operator can take multiple arguments (which is needed for efficiently PUPing arrays).

The bar syntax will be able to copy any structure, whether it has a pup method or not. If there is no pup method, the C++ operator overloading rules decay the bar operator into packing the bytes of the structure, which will work fine for simple types on homogenous machines. For dynamically allocated structures or heterogeneous migration, you'll need to define a pup method for all packed classes/structures. As an added benefit, the same pup methods will get called during parameter marshalling.

June 29, 2008
Charm Homepage