Feature #1802: Direct API for the generic Layer to perform nocopy operations 67/2967/32
authorNitin Bhat <nbhat4@illinois.edu>
Mon, 9 Oct 2017 14:44:13 +0000 (09:44 -0500)
committerNitin Bhat <nbhat4@illinois.edu>
Tue, 6 Mar 2018 15:52:13 +0000 (09:52 -0600)
This API is an alternative to the existing nocopy api that uses entry method specifiers to perform
zerocopy operations under the hood. This API allows users to directly pass nocopy objects
like CkNcpySource and CkNcpyDestination to perform zerocopy operations like rget and rput. This gerrit
change includes the generic layer implementation along with examples.

Change-Id: I4fc56951989fca8a962be87f7f8d49c99e2949a0

32 files changed:
examples/charm++/zerocopy/Makefile
examples/charm++/zerocopy/direct_api/Makefile [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/get_put_pingpong/Makefile [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/get_put_pingpong/get_put_pingpong.C [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/get_put_pingpong/get_put_pingpong.ci [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/pingpong/Makefile [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/pingpong/pingpong.C [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/pingpong/pingpong.ci [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/simple_rget/Makefile [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/simple_rget/simple_rget.C [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/simple_rget/simple_rget.ci [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/simple_rput/Makefile [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/simple_rput/simple_rput.C [new file with mode: 0644]
examples/charm++/zerocopy/direct_api/simple_rput/simple_rput.ci [new file with mode: 0644]
examples/charm++/zerocopy/entry_method_api/Makefile [new file with mode: 0644]
examples/charm++/zerocopy/entry_method_api/pingpong/Makefile [moved from examples/charm++/zerocopy/pingpong/Makefile with 84% similarity]
examples/charm++/zerocopy/entry_method_api/pingpong/pingpong.C [moved from examples/charm++/zerocopy/pingpong/pingpong.C with 98% similarity]
examples/charm++/zerocopy/entry_method_api/pingpong/pingpong.ci [moved from examples/charm++/zerocopy/pingpong/pingpong.ci with 100% similarity]
examples/charm++/zerocopy/entry_method_api/simpleZeroCopy/Makefile [moved from examples/charm++/zerocopy/simpleZeroCopy/Makefile with 87% similarity]
examples/charm++/zerocopy/entry_method_api/simpleZeroCopy/simpleZeroCopy.C [moved from examples/charm++/zerocopy/simpleZeroCopy/simpleZeroCopy.C with 100% similarity]
examples/charm++/zerocopy/entry_method_api/simpleZeroCopy/simpleZeroCopy.ci [moved from examples/charm++/zerocopy/simpleZeroCopy/simpleZeroCopy.ci with 100% similarity]
examples/charm++/zerocopy/entry_method_api/stencil3d/Makefile [moved from examples/charm++/zerocopy/stencil3d/Makefile with 91% similarity]
examples/charm++/zerocopy/entry_method_api/stencil3d/stencil3d.C [moved from examples/charm++/zerocopy/stencil3d/stencil3d.C with 99% similarity]
examples/charm++/zerocopy/entry_method_api/stencil3d/stencil3d.ci [moved from examples/charm++/zerocopy/stencil3d/stencil3d.ci with 100% similarity]
examples/common.mk
src/ck-core/ckrdma.C
src/ck-core/ckrdma.h
src/ck-core/init.C
src/conv-core/conv-rdma.c [new file with mode: 0644]
src/conv-core/conv-rdma.h
src/conv-core/convcore.c
src/scripts/Makefile

index 4225c75f6116d36f5a1c31a99eb2c3011d7b684e..c05621ba16af1ea9d94d45daaa17b9f01c4a18d2 100644 (file)
@@ -1,4 +1,4 @@
-DIRS   = pingpong simpleZeroCopy stencil3d
+DIRS   = direct_api entry_method_api
 
 all:
        for d in $(DIRS); do \
diff --git a/examples/charm++/zerocopy/direct_api/Makefile b/examples/charm++/zerocopy/direct_api/Makefile
new file mode 100644 (file)
index 0000000..e32d5ab
--- /dev/null
@@ -0,0 +1,16 @@
+DIRS   = simple_rget simple_rput get_put_pingpong pingpong
+
+all:
+       for d in $(DIRS); do \
+               ($(MAKE) -C $$d all OPTS='$(OPTS)' || exit 1) || exit 1; \
+       done
+
+test:
+       for d in $(DIRS); do \
+               ($(MAKE) -C $$d test OPTS='$(OPTS)' TESTOPTS='$(TESTOPTS)' || exit 1) || exit 1; \
+       done
+
+clean:
+       for d in $(DIRS); do ($(MAKE) -C $$d clean OPTS='$(OPTS)'); done
+       rm -f TAGS #*#
+       rm -f core *~
diff --git a/examples/charm++/zerocopy/direct_api/get_put_pingpong/Makefile b/examples/charm++/zerocopy/direct_api/get_put_pingpong/Makefile
new file mode 100644 (file)
index 0000000..fce5946
--- /dev/null
@@ -0,0 +1,23 @@
+-include ../../../../common.mk
+CHARMC=../../../../../bin/charmc $(OPTS)
+
+all: get_put_pingpong
+
+OBJS = get_put_pingpong.o
+
+get_put_pingpong: $(OBJS)
+       $(CHARMC) -language charm++ -o get_put_pingpong $(OBJS)
+
+cifiles: get_put_pingpong.ci
+       $(CHARMC)  get_put_pingpong.ci
+       touch cifiles
+
+get_put_pingpong.o: get_put_pingpong.C cifiles
+       $(CHARMC) -c get_put_pingpong.C
+
+test: all
+       $(call run, +p1 ./get_put_pingpong 20 )
+       $(call run, +p2 ./get_put_pingpong 20 )
+
+clean:
+       rm -f *.decl.h *.def.h conv-host *.o get_put_pingpong charmrun cifiles
diff --git a/examples/charm++/zerocopy/direct_api/get_put_pingpong/get_put_pingpong.C b/examples/charm++/zerocopy/direct_api/get_put_pingpong/get_put_pingpong.C
new file mode 100644 (file)
index 0000000..8544cb2
--- /dev/null
@@ -0,0 +1,179 @@
+#include "simple_direct.decl.h"
+#include <assert.h>
+
+CProxy_main mainProxy;
+class main : public CBase_main
+{
+  CProxy_Ping1 arr1;
+  int count;
+public:
+  main(CkMigrateMessage *m) {}
+  main(CkArgMsg *m)
+  {
+    if(CkNumPes()>2) {
+      CkAbort("Run this program on 1 or 2 processors only.\n");
+    }
+    if(m->argc !=2 ) {
+      CkAbort("Usage: ./simple_direct <array size>\n");
+    }
+    int size = atoi(m->argv[1]);
+    mainProxy = thisProxy;
+    delete m;
+    arr1 = CProxy_Ping1::ckNew(size, 2);
+    count = 0;
+    arr1[0].start();
+  };
+
+  void maindone(){
+    count++;
+    if(count == 2) {
+      CkPrintf("[%d][%d] Result validated! \n", CkMyPe(), CkMyNode());
+      CkExit();
+    }
+  };
+};
+
+template<class T>
+void compareArray(T *&aArr, T *&bArr, int size){
+  for(int i=0; i<size; i++)
+    assert(aArr[i] == bArr[i]);
+}
+
+template<class T>
+void assignValues(T *&arr, int size){
+  arr = new T[size];
+  for(int i=0; i<size; i++)
+     arr[i] = rand() % 100 + 1;
+}
+
+void assignCharValues(char *&arr, int size){
+  arr = new char[size];
+  for(int i=0; i<size; i++)
+     arr[i] = (char)(rand() % 125 + 1);
+}
+
+class Ping1 : public CBase_Ping1
+{
+  int *iArr1, *iArr2;
+  char *cArr1, *cArr2;
+  double *dArr1, *dArr2;
+  int size;
+  int otherIndex, recvCbCounter, sendCbCounter;
+  CkCallback sendCb, recvCb;
+  CkNcpyDestination myDest1, myDest2, myDest3;
+  CkNcpySource mySrc1, mySrc2, mySrc3;
+  CkNcpyDestination otherDest1, otherDest2, otherDest3;
+
+public:
+  Ping1(int size)
+  {
+    this->size = size;
+
+    // original arrays that contains data
+    assignValues(iArr1, size);
+    assignValues(dArr1, size);
+    assignCharValues(cArr1, size);
+
+    sendCb = CkCallback(CkIndex_Ping1::senderCallback(NULL), thisProxy[thisIndex]);
+    recvCb = CkCallback(CkIndex_Ping1::receiverCallback(NULL), thisProxy[thisIndex]);
+
+    otherIndex = (thisIndex + 1) % 2;
+    sendCbCounter = 0;
+    recvCbCounter = 0;
+  }
+  Ping1(CkMigrateMessage *m) {}
+
+  // Executed on Index 0
+  void start()
+  {
+    CkAssert(thisIndex == 0);
+    mySrc1 = CkNcpySource(iArr1, size*sizeof(int), sendCb);
+    mySrc2 = CkNcpySource(dArr1, size*sizeof(double), sendCb);
+    mySrc3 = CkNcpySource(cArr1, size*sizeof(char), sendCb);
+
+    iArr2 = new int[size];
+    dArr2 = new double[size];
+    cArr2 = new char[size];
+
+    myDest1 = CkNcpyDestination(iArr2, size*sizeof(int), recvCb);
+    myDest2 = CkNcpyDestination(dArr2, size*sizeof(double), recvCb);
+    myDest3 = CkNcpyDestination(cArr2, size*sizeof(char), recvCb);
+
+    thisProxy[otherIndex].recvNcpyInfo(mySrc1, mySrc2, mySrc3, myDest1, myDest2, myDest3);
+  }
+
+  void senderCallback(CkDataMsg *m){
+    sendCbCounter++;
+    if(sendCbCounter == 3) {
+      // Release Resources for my sources
+      mySrc1.releaseResource();
+      mySrc2.releaseResource();
+      mySrc3.releaseResource();
+
+      if(thisIndex == 1){
+        delete [] iArr1;
+        delete [] dArr1;
+        delete [] cArr1;
+        mainProxy.maindone();
+      }
+    }
+    delete m;
+  }
+
+  void receiverCallback(CkDataMsg *m){
+    recvCbCounter++;
+    if(recvCbCounter == 3) {
+
+      // Release Resources for my destinations
+      myDest1.releaseResource();
+      myDest2.releaseResource();
+      myDest3.releaseResource();
+
+      if(thisIndex == 1){
+        CkPrintf("[%d][%d][%d] Rget call completed\n", thisIndex, CkMyPe(), CkMyNode());
+
+        // Create a nocopy sources for me to Rput from into destinations received
+        mySrc1 = CkNcpySource(iArr1, sizeof(int)*size, sendCb);
+        mySrc2 = CkNcpySource(dArr1, sizeof(double)*size, sendCb);
+        mySrc3 = CkNcpySource(cArr1, sizeof(char)*size, sendCb);
+
+        // Index 1 Rputting to 0
+        mySrc1.rput(otherDest1);
+        mySrc2.rput(otherDest2);
+        mySrc3.rput(otherDest3);
+
+      } else {
+        CkPrintf("[%d][%d][%d] Rput call completed\n", thisIndex, CkMyPe(), CkMyNode());
+
+        compareArray(iArr1, iArr2, size);
+        compareArray(dArr1, dArr2, size);
+        compareArray(cArr1, cArr2, size);
+
+        // All arrays can be deleted at this point. But they are not as the program is exiting.
+        mainProxy.maindone();
+      }
+    }
+    delete m;
+  }
+
+  // Executed on Index 1
+  void recvNcpyInfo(CkNcpySource src1, CkNcpySource src2, CkNcpySource src3, CkNcpyDestination dest1, CkNcpyDestination dest2, CkNcpyDestination dest3)
+  {
+    CkAssert(thisIndex == 1);
+    otherDest1 = dest1;
+    otherDest2 = dest2;
+    otherDest3 = dest3;
+
+    // Create nocopy destinations for me to Rget from sources received
+    myDest1 = CkNcpyDestination(iArr1, size*sizeof(int), recvCb);
+    myDest2 = CkNcpyDestination(dArr1, size*sizeof(double), recvCb);
+    myDest3 = CkNcpyDestination(cArr1, size*sizeof(char), recvCb);
+
+    // Index 1 Rgetting from 0
+    myDest1.rget(src1);
+    myDest2.rget(src2);
+    myDest3.rget(src3);
+  }
+};
+
+#include "simple_direct.def.h"
diff --git a/examples/charm++/zerocopy/direct_api/get_put_pingpong/get_put_pingpong.ci b/examples/charm++/zerocopy/direct_api/get_put_pingpong/get_put_pingpong.ci
new file mode 100644 (file)
index 0000000..6f93c89
--- /dev/null
@@ -0,0 +1,18 @@
+mainmodule simple_direct {
+
+  readonly CProxy_main mainProxy;
+
+  mainchare main {
+    entry main(CkArgMsg *m);
+    entry void maindone();
+  };
+
+  array [1D] Ping1 {
+    entry Ping1(int size);
+    entry void start();
+    entry void senderCallback(CkDataMsg *m);
+    entry void receiverCallback(CkDataMsg *m);
+    entry void recvNcpyInfo(CkNcpySource src1, CkNcpySource src2, CkNcpySource src3, CkNcpyDestination dest1, CkNcpyDestination dest2, CkNcpyDestination dest3);
+  };
+
+};
diff --git a/examples/charm++/zerocopy/direct_api/pingpong/Makefile b/examples/charm++/zerocopy/direct_api/pingpong/Makefile
new file mode 100644 (file)
index 0000000..f94bb4e
--- /dev/null
@@ -0,0 +1,23 @@
+-include ../../../../common.mk
+CHARMC=../../../../../bin/charmc $(OPTS)
+
+all: pingpong
+
+OBJS = pingpong.o
+
+pingpong: $(OBJS)
+       $(CHARMC) -language charm++ -o pingpong $(OBJS)
+
+cifiles: pingpong.ci
+       $(CHARMC)  pingpong.ci
+       touch cifiles
+
+pingpong.o: pingpong.C cifiles
+       $(CHARMC) -c pingpong.C
+
+test: all
+       $(call run, +p1 ./pingpong ++timeout 200)
+       $(call run, +p2 ./pingpong ++timeout 200)
+
+clean:
+       rm -f *.decl.h *.def.h conv-host *.o pingpong charmrun cifiles
diff --git a/examples/charm++/zerocopy/direct_api/pingpong/pingpong.C b/examples/charm++/zerocopy/direct_api/pingpong/pingpong.C
new file mode 100644 (file)
index 0000000..27c1ac4
--- /dev/null
@@ -0,0 +1,234 @@
+#include "pingpong.decl.h"
+
+#define BIG_ITER 1000
+#define SMALL_ITER 100
+
+#define MAX_PAYLOAD 1 << 23
+
+CProxy_main mainProxy;
+bool warmUp;
+
+class main : public CBase_main
+{
+  CProxy_Ping1 arr1;
+  int size;
+  public:
+  main(CkMigrateMessage *m) {}
+  main(CkArgMsg *m)
+  {
+    if(CkNumPes()>2) {
+      CkAbort("Run this program on 1 or 2 processors only.\n");
+    }
+    delete m;
+    size = 512;
+    mainProxy = thisProxy;
+    warmUp = true;
+    CkPrintf("Size (bytes) \t\tIterations\t\tRegular API (one-way us)\tDirect Get Get (one-way us)\tDirect Put Put (one-way us)\n");
+    arr1 = CProxy_Ping1::ckNew(2);
+    CkStartQD(CkCallback(CkIndex_main::maindone(), mainProxy));
+  };
+
+  void maindone(void){
+    if(size < MAX_PAYLOAD) {
+      arr1[0].start(size);
+      size = size << 1;
+    } else if(size == MAX_PAYLOAD) {
+      arr1[0].freeBuffer();
+    }
+  }
+};
+
+class Ping1 : public CBase_Ping1
+{
+  int size;
+  int niter;
+  int iterations;
+  int counter;
+  int otherIndex;
+  double start_time, end_time, reg_time, zcpy_time1, zcpy_time2;
+  CkNcpySource mySrc;
+  CkNcpyDestination myDest;
+  char *nocopyMsg, *otherMsg;
+
+  public:
+  Ping1()
+  {
+    nocopyMsg = new char[MAX_PAYLOAD];
+    otherMsg = new char[MAX_PAYLOAD];
+    niter = 0;
+    otherIndex = (thisIndex + 1) % 2;
+  }
+
+  Ping1(CkMigrateMessage *m) {}
+
+  void start(int size)
+  {
+    counter = 0;
+    this->size = size;
+    if(size >= 1 << 20)
+      iterations = SMALL_ITER;
+    else
+      iterations = BIG_ITER;
+
+    start_time = CkWallTimer();
+    // send CkNcpySource to 1
+    thisProxy[1].recv(nocopyMsg, size);
+  }
+
+  void recv(char *msg, int size) {
+    //copy into the user's buffer
+    memcpy(otherMsg, msg, size);
+    if(thisIndex==0) {
+      niter++;
+      if(niter==iterations) {
+        end_time = CkWallTimer();
+        reg_time = 1.0e6*(end_time-start_time)/iterations;
+        thisProxy.setupGetGetPingpong(size);
+      } else {
+        thisProxy[1].recv(nocopyMsg, size);
+      }
+    } else {
+      thisProxy[0].recv(nocopyMsg, size);
+    }
+  }
+
+  void setupGetGetPingpong(int size) {
+    // Source callback and Ncpy object
+    CkCallback srcCb = CkCallback(CkCallback::ignore);
+    mySrc = CkNcpySource(nocopyMsg, sizeof(char)*size, srcCb);
+
+    // Destination callback and Ncpy object
+    CkCallback destCb = CkCallback(CkIndex_Ping1::callbackGetGetPingpong(NULL), thisProxy[thisIndex]);
+    myDest = CkNcpyDestination(otherMsg, sizeof(char)*size, destCb);
+
+    thisProxy[0].beginGetGetPingpong();
+  }
+
+  void beginGetGetPingpong() {
+    counter++;
+    if(counter == 2) {
+      niter=0;
+      start_time = CkWallTimer();
+      thisProxy[1].recvNcpySrcInfo(mySrc);
+    }
+  }
+
+  void recvNcpySrcInfo(CkNcpySource otherSrc) {
+    myDest.rget(otherSrc);
+  }
+
+  void callbackGetGetPingpong(CkDataMsg *m) {
+    if(thisIndex == 0) {
+      // iteration completed
+      niter++;
+      if(niter == iterations) {
+        end_time = CkWallTimer();
+        zcpy_time1 = 1.0e6*(end_time - start_time)/iterations;
+        niter = 0;
+        thisProxy.endGetGetPingpong();
+      } else {
+        thisProxy[1].recvNcpySrcInfo(mySrc);
+      }
+    } else {
+      thisProxy[0].recvNcpySrcInfo(mySrc);
+    }
+  }
+
+  void endGetGetPingpong() {
+    counter = 0;
+    mySrc.releaseResource();
+    myDest.releaseResource();
+    thisProxy[0].doneGetGetPingpong();
+  }
+
+  void doneGetGetPingpong() {
+    counter++;
+    if(counter == 2) {
+      counter = 0;
+      thisProxy.setupPutPutPingpong(size);
+    }
+  }
+
+  void setupPutPutPingpong(int size) {
+
+    // Source callback and Ncpy object
+    CkCallback srcCb = CkCallback(CkCallback::ignore);
+    mySrc = CkNcpySource(nocopyMsg, sizeof(char)*size, srcCb);
+
+    // Destination callback and Ncpy object
+    CkCallback destCb = CkCallback(CkIndex_Ping1::callbackPutPutPingpong(NULL), thisProxy[thisIndex]);
+    myDest = CkNcpyDestination(otherMsg, sizeof(char)*size, destCb);
+
+    thisProxy[0].beginPutPutPingpong();
+  }
+
+  void beginPutPutPingpong() {
+    counter++;
+    if(counter == 2) {
+      counter = 0;
+      niter=0;
+      start_time = CkWallTimer();
+      thisProxy[1].askNcpyDestInfo();
+    }
+  }
+
+  void askNcpyDestInfo() {
+    thisProxy[otherIndex].recvNcpyDestInfo(myDest);
+  }
+
+  void recvNcpyDestInfo(CkNcpyDestination otherDest) {
+    mySrc.rput(otherDest);
+  }
+
+  void callbackPutPutPingpong(CkDataMsg *m) {
+    if(thisIndex == 0) {
+      // iteration completed
+      niter++;
+      if(niter == iterations) {
+        end_time = CkWallTimer();
+        zcpy_time2 = 1.0e6*(end_time - start_time)/iterations;
+        niter = 0;
+        if(warmUp) {
+          warmUp = false;
+        } else {
+          if(size < 1 << 24)
+            CkPrintf("%d\t\t\t%d\t\t\t%lf\t\t\t%lf\t\t\t%lf\n", size, iterations, reg_time/2, zcpy_time1/2, zcpy_time2/2);
+          else //using different print format for larger numbers for aligned output
+            CkPrintf("%d\t\t%d\t\t\t%lf\t\t\t%lf\t\t\t%lf\n", size, iterations, reg_time/2, zcpy_time1/2, zcpy_time2/2);
+        }
+        thisProxy.endPutPutPingpong();
+      } else {
+        thisProxy[1].askNcpyDestInfo();
+      }
+    } else {
+      thisProxy[0].askNcpyDestInfo();
+    }
+  }
+
+  void endPutPutPingpong() {
+    mySrc.releaseResource();
+    myDest.releaseResource();
+    thisProxy[0].donePutPutPingpong();
+  }
+
+  void donePutPutPingpong() {
+    counter++;
+    if(counter == 2) {
+      counter = 0;
+      mainProxy.maindone();
+    }
+  }
+
+  void freeBuffer(){
+    delete [] nocopyMsg;
+    delete [] otherMsg;
+    if(thisIndex == 0){
+      thisProxy[1].freeBuffer();
+    }
+    else{
+      CkExit();
+    }
+  }
+};
+
+#include "pingpong.def.h"
diff --git a/examples/charm++/zerocopy/direct_api/pingpong/pingpong.ci b/examples/charm++/zerocopy/direct_api/pingpong/pingpong.ci
new file mode 100644 (file)
index 0000000..d9c6081
--- /dev/null
@@ -0,0 +1,37 @@
+mainmodule pingpong {
+
+  readonly CProxy_main mainProxy;
+  readonly bool warmUp;
+
+  mainchare main {
+    entry main(CkArgMsg *m);
+    entry void maindone();
+  };
+
+  array [1D] Ping1 {
+    entry Ping1();
+    entry void start(int size);
+
+    // Method for regular API pingpong
+    entry void recv(char msg[size], int size);
+
+    // Methods for Get Get Pingpong using the Ncpy Direct API
+    entry void setupGetGetPingpong(int size);
+    entry void beginGetGetPingpong();
+    entry void callbackGetGetPingpong(CkDataMsg *m);
+    entry void recvNcpySrcInfo(CkNcpySource src);
+    entry void endGetGetPingpong();
+    entry void doneGetGetPingpong();
+
+    // Methods for Put Put Pingpong using the Ncpy Direct API
+    entry void setupPutPutPingpong(int size);
+    entry void beginPutPutPingpong();
+    entry void callbackPutPutPingpong(CkDataMsg *m);
+    entry void askNcpyDestInfo();
+    entry void recvNcpyDestInfo(CkNcpyDestination dest);
+    entry void endPutPutPingpong();
+    entry void donePutPutPingpong();
+
+    entry void freeBuffer();
+  };
+};
diff --git a/examples/charm++/zerocopy/direct_api/simple_rget/Makefile b/examples/charm++/zerocopy/direct_api/simple_rget/Makefile
new file mode 100644 (file)
index 0000000..fe1f1bc
--- /dev/null
@@ -0,0 +1,23 @@
+-include ../../../../common.mk
+CHARMC=../../../../../bin/charmc $(OPTS)
+
+all: simple_rget
+
+OBJS = simple_rget.o
+
+simple_rget: $(OBJS)
+       $(CHARMC) -language charm++ -o simple_rget $(OBJS)
+
+cifiles: simple_rget.ci
+       $(CHARMC)  simple_rget.ci
+       touch cifiles
+
+simple_rget.o: simple_rget.C cifiles
+       $(CHARMC) -c simple_rget.C
+
+test: all
+       $(call run, +p1 ./simple_rget 20 )
+       $(call run, +p2 ./simple_rget 20 )
+
+clean:
+       rm -f *.decl.h *.def.h conv-host *.o simple_rget charmrun cifiles
diff --git a/examples/charm++/zerocopy/direct_api/simple_rget/simple_rget.C b/examples/charm++/zerocopy/direct_api/simple_rget/simple_rget.C
new file mode 100644 (file)
index 0000000..7ba8ae2
--- /dev/null
@@ -0,0 +1,177 @@
+#include "simple_rget.decl.h"
+#include <assert.h>
+
+CProxy_main mainProxy;
+class main : public CBase_main
+{
+  CProxy_Ping1 arr1;
+  int count;
+public:
+  main(CkMigrateMessage *m) {}
+  main(CkArgMsg *m)
+  {
+    if(CkNumPes()>2) {
+      CkAbort("Run this program on 1 or 2 processors only.\n");
+    }
+    if(m->argc !=2 ) {
+      CkAbort("Usage: ./simple_rget <array size>\n");
+    }
+    int size = atoi(m->argv[1]);
+    mainProxy = thisProxy;
+    delete m;
+    arr1 = CProxy_Ping1::ckNew(size, 2);
+    count = 0;
+    arr1[0].start();
+  };
+
+  void maindone(){
+    count++;
+    if(count == 2) {
+      CkExit();
+    }
+  };
+};
+
+template<class T>
+void compareArray(T *&aArr, T *&bArr, int size){
+  for(int i=0; i<size; i++)
+    assert(aArr[i] == bArr[i]);
+}
+
+template<class T>
+void assignValues(T *&arr, int size){
+  arr = new T[size];
+  for(int i=0; i<size; i++)
+     arr[i] = rand() % 100 + 1;
+}
+
+void assignCharValues(char *&arr, int size){
+  arr = new char[size];
+  for(int i=0; i<size; i++)
+     arr[i] = (char)(rand() % 125 + 1);
+}
+
+class Ping1 : public CBase_Ping1
+{
+  int *iArr1;
+  char *cArr1;
+  double *dArr1;
+  int size;
+  int otherIndex, cbCounter, valCounter;
+  CkCallback cb;
+  CkNcpyDestination myDest1, myDest2, myDest3;
+  CkNcpySource mySrc1, mySrc2, mySrc3;
+
+public:
+  Ping1(int size)
+  {
+    this->size = size;
+
+    if(thisIndex == 0) {
+      // original arrays that contains data
+      assignValues(iArr1, size);
+      assignValues(dArr1, size);
+      assignCharValues(cArr1, size);
+      // Set GET Sender callback
+      cb = CkCallback(CkIndex_Ping1::getSenderDone(NULL), thisProxy[thisIndex]);
+    } else {
+      iArr1 = new int[size];
+      cArr1 = new char[size];
+      dArr1 = new double[size];
+      // Set GET Receiver callback
+      cb = CkCallback(CkIndex_Ping1::getReceiverDone(NULL), thisProxy[thisIndex]);
+    }
+
+    otherIndex = (thisIndex + 1) % 2;
+    cbCounter = 0;
+    valCounter = 0;
+  }
+  Ping1(CkMigrateMessage *m) {}
+
+  // Executed on Index 0
+  void start()
+  {
+    CkAssert(thisIndex == 0);
+    mySrc1 = CkNcpySource(iArr1, size*sizeof(int), cb);
+    mySrc2 = CkNcpySource(dArr1, size*sizeof(double), cb);
+    mySrc3 = CkNcpySource(cArr1, size*sizeof(char), cb);
+
+    // Send my sources to Index 1; Index 1 performs Rgets from these sources
+    thisProxy[otherIndex].recvNcpyInfo(mySrc1, mySrc2, mySrc3);
+  }
+
+  // Executed on Index 0
+  void getSenderDone(CkDataMsg *m){
+    CkAssert(thisIndex == 0);
+    cbCounter++;
+    if(cbCounter == 3) {
+      // Release Resources for my sources
+      mySrc1.releaseResource();
+      mySrc2.releaseResource();
+      mySrc3.releaseResource();
+      CkPrintf("[%d][%d][%d] Rget Source Done\n", thisIndex, CkMyPe(), CkMyNode());
+      sendValidationData();
+    }
+    delete m;
+  }
+
+  // Executed on Index 1 (which receives data from rget)
+  void getReceiverDone(CkDataMsg *m){
+    CkAssert(thisIndex == 1);
+    cbCounter++;
+    if(cbCounter == 3) {
+      // Release Resources for my destinations
+      myDest1.releaseResource();
+      myDest2.releaseResource();
+      myDest3.releaseResource();
+      CkPrintf("[%d][%d][%d] Rget Destination Done\n", thisIndex, CkMyPe(), CkMyNode());
+      thisProxy[otherIndex].sendValidationData();
+    }
+    delete m;
+  }
+
+  // Executed on Index 0
+  void sendValidationData() {
+    CkAssert(thisIndex == 0);
+    valCounter++;
+    if(valCounter == 2) {
+      thisProxy[otherIndex].validateGetData(iArr1, dArr1, cArr1, size);
+      delete [] iArr1;
+      delete [] dArr1;
+      delete [] cArr1;
+      mainProxy.maindone();
+    }
+  }
+
+  // Executed on Index 1
+  void recvNcpyInfo(CkNcpySource src1, CkNcpySource src2, CkNcpySource src3)
+  {
+    CkAssert(thisIndex == 1);
+    // Create nocopy destination for me to Rget into
+    myDest1 = CkNcpyDestination(iArr1, size*sizeof(int), cb);
+    myDest2 = CkNcpyDestination(dArr1, size*sizeof(double), cb);
+    myDest3 = CkNcpyDestination(cArr1, size*sizeof(char), cb);
+
+    // Perform Rget from Index 0's sources into my destinations
+    myDest1.rget(src1);
+    myDest2.rget(src2);
+    myDest3.rget(src3);
+  }
+
+  // Executed on Index 1
+  void validateGetData(int *iArr2, double *dArr2, char *cArr2, int size)
+  {
+    CkAssert(thisIndex == 1);
+    compareArray(iArr1, iArr2, size);
+    compareArray(dArr1, dArr2, size);
+    compareArray(cArr1, cArr2, size);
+    CkPrintf("[%d][%d][%d] Rget Validated! \n", thisIndex, CkMyPe(), CkMyNode());
+    delete [] iArr1;
+    delete [] dArr1;
+    delete [] cArr1;
+    mainProxy.maindone();
+  }
+
+};
+
+#include "simple_rget.def.h"
diff --git a/examples/charm++/zerocopy/direct_api/simple_rget/simple_rget.ci b/examples/charm++/zerocopy/direct_api/simple_rget/simple_rget.ci
new file mode 100644 (file)
index 0000000..06db1f4
--- /dev/null
@@ -0,0 +1,20 @@
+mainmodule simple_rget {
+
+  readonly CProxy_main mainProxy;
+
+  mainchare main {
+    entry main(CkArgMsg *m);
+    entry void maindone();
+  };
+
+  array [1D] Ping1 {
+    entry Ping1(int size);
+    entry void start();
+    entry void getSenderDone(CkDataMsg *m);
+    entry void getReceiverDone(CkDataMsg *m);
+    entry void recvNcpyInfo(CkNcpySource src1, CkNcpySource src2, CkNcpySource src3);
+    entry void sendValidationData();
+    entry void validateGetData(int iArr2[size], double dArr2[size], char cArr2[size], int size);
+  };
+
+};
diff --git a/examples/charm++/zerocopy/direct_api/simple_rput/Makefile b/examples/charm++/zerocopy/direct_api/simple_rput/Makefile
new file mode 100644 (file)
index 0000000..e1c2949
--- /dev/null
@@ -0,0 +1,23 @@
+-include ../../../../common.mk
+CHARMC=../../../../../bin/charmc $(OPTS)
+
+all: simple_rput
+
+OBJS = simple_rput.o
+
+simple_rput: $(OBJS)
+       $(CHARMC) -language charm++ -o simple_rput $(OBJS)
+
+cifiles: simple_rput.ci
+       $(CHARMC)  simple_rput.ci
+       touch cifiles
+
+simple_rput.o: simple_rput.C cifiles
+       $(CHARMC) -c simple_rput.C
+
+test: all
+       $(call run, +p1 ./simple_rput 20 )
+       $(call run, +p2 ./simple_rput 20 )
+
+clean:
+       rm -f *.decl.h *.def.h conv-host *.o simple_rput charmrun cifiles
diff --git a/examples/charm++/zerocopy/direct_api/simple_rput/simple_rput.C b/examples/charm++/zerocopy/direct_api/simple_rput/simple_rput.C
new file mode 100644 (file)
index 0000000..d9a9d68
--- /dev/null
@@ -0,0 +1,177 @@
+#include "simple_rput.decl.h"
+#include <assert.h>
+
+CProxy_main mainProxy;
+class main : public CBase_main
+{
+  CProxy_Ping1 arr1;
+  int count;
+public:
+  main(CkMigrateMessage *m) {}
+  main(CkArgMsg *m)
+  {
+    if(CkNumPes()>2) {
+      CkAbort("Run this program on 1 or 2 processors only.\n");
+    }
+    if(m->argc !=2 ) {
+      CkAbort("Usage: ./simple_rput <array size>\n");
+    }
+    int size = atoi(m->argv[1]);
+    mainProxy = thisProxy;
+    delete m;
+    arr1 = CProxy_Ping1::ckNew(size, 2);
+    count = 0;
+    arr1[1].start();
+  };
+
+  void maindone(){
+    count++;
+    if(count == 2) {
+      CkExit();
+    }
+  };
+};
+
+template<class T>
+void compareArray(T *&aArr, T *&bArr, int size){
+  for(int i=0; i<size; i++)
+    assert(aArr[i] == bArr[i]);
+}
+
+template<class T>
+void assignValues(T *&arr, int size){
+  arr = new T[size];
+  for(int i=0; i<size; i++)
+     arr[i] = rand() % 100 + 1;
+}
+
+void assignCharValues(char *&arr, int size){
+  arr = new char[size];
+  for(int i=0; i<size; i++)
+     arr[i] = (char)(rand() % 125 + 1);
+}
+
+class Ping1 : public CBase_Ping1
+{
+  int *iArr1;
+  char *cArr1;
+  double *dArr1;
+  int size;
+  int otherIndex, cbCounter, valCounter;
+  CkCallback cb;
+  CkNcpyDestination myDest1, myDest2, myDest3;
+  CkNcpySource mySrc1, mySrc2, mySrc3;
+
+public:
+  Ping1(int size)
+  {
+    this->size = size;
+
+    if(thisIndex == 0) {
+      // original arrays that contains data
+      assignValues(iArr1, size);
+      assignValues(dArr1, size);
+      assignCharValues(cArr1, size);
+      // Set PUT Sender callback
+      cb = CkCallback(CkIndex_Ping1::putSenderDone(NULL), thisProxy[thisIndex]);
+    } else {
+      iArr1 = new int[size];
+      cArr1 = new char[size];
+      dArr1 = new double[size];
+      // Set PUT Receiver callback
+      cb = CkCallback(CkIndex_Ping1::putReceiverDone(NULL), thisProxy[thisIndex]);
+    }
+
+    otherIndex = (thisIndex + 1) % 2;
+    cbCounter = 0;
+    valCounter = 0;
+  }
+  Ping1(CkMigrateMessage *m) {}
+
+  // Executed on Index 1
+  void start()
+  {
+    CkAssert(thisIndex == 1);
+    myDest1 = CkNcpyDestination(iArr1, size*sizeof(int), cb);
+    myDest2 = CkNcpyDestination(dArr1, size*sizeof(double), cb);
+    myDest3 = CkNcpyDestination(cArr1, size*sizeof(char), cb);
+
+    // Send my destinations to Index 0; Index 0 performs Rputs into these destinations
+    thisProxy[otherIndex].recvNcpyInfo(myDest1, myDest2, myDest3);
+  }
+
+  // Executed on Index 0 (which calls rput)
+  void putSenderDone(CkDataMsg *m){
+    CkAssert(thisIndex == 0);
+    cbCounter++;
+    if(cbCounter == 3) {
+      // Release Resources for my sources
+      mySrc1.releaseResource();
+      mySrc2.releaseResource();
+      mySrc3.releaseResource();
+      CkPrintf("[%d][%d][%d] Rput Source Done\n", thisIndex, CkMyPe(), CkMyNode());
+      sendValidationData();
+    }
+    delete m;
+  }
+
+  // Executed on Index 1 (which receives data from rput)
+  void putReceiverDone(CkDataMsg *m){
+    CkAssert(thisIndex == 1);
+    cbCounter++;
+    if(cbCounter == 3) {
+      // Release Resources for my destinations
+      myDest1.releaseResource();
+      myDest2.releaseResource();
+      myDest3.releaseResource();
+      CkPrintf("[%d][%d][%d] Rput Destination Done\n", thisIndex, CkMyPe(), CkMyNode());
+      thisProxy[otherIndex].sendValidationData();
+    }
+    delete m;
+  }
+
+  // Executed on Index 0
+  void sendValidationData() {
+    CkAssert(thisIndex == 0);
+    valCounter++;
+    if(valCounter == 2) {
+      thisProxy[otherIndex].validatePutData(iArr1, dArr1, cArr1, size);
+      delete [] iArr1;
+      delete [] dArr1;
+      delete [] cArr1;
+      mainProxy.maindone();
+    }
+  }
+
+  // Executed on Index 0
+  void recvNcpyInfo(CkNcpyDestination dest1, CkNcpyDestination dest2, CkNcpyDestination dest3)
+  {
+    CkAssert(thisIndex == 0);
+    // Create nocopy sources for me to Rput into
+    mySrc1 = CkNcpySource(iArr1, size*sizeof(int), cb);
+    mySrc2 = CkNcpySource(dArr1, size*sizeof(double), cb);
+    mySrc3 = CkNcpySource(cArr1, size*sizeof(char), cb);
+
+    // Perform Rputs from my sources into Index 1's destinations
+    mySrc1.rput(dest1);
+    mySrc2.rput(dest2);
+    mySrc3.rput(dest3);
+  }
+
+  // Executed on Index 1
+  void validatePutData(int *iArr2, double *dArr2, char *cArr2, int size)
+  {
+    CkAssert(thisIndex == 1);
+    compareArray(iArr1, iArr2, size);
+    compareArray(dArr1, dArr2, size);
+    compareArray(cArr1, cArr2, size);
+    CkPrintf("[%d][%d][%d] Rput Validated! \n", thisIndex, CkMyPe(), CkMyNode());
+    delete [] iArr1;
+    delete [] dArr1;
+    delete [] cArr1;
+    mainProxy.maindone();
+  }
+
+};
+
+#include "simple_rput.def.h"
diff --git a/examples/charm++/zerocopy/direct_api/simple_rput/simple_rput.ci b/examples/charm++/zerocopy/direct_api/simple_rput/simple_rput.ci
new file mode 100644 (file)
index 0000000..a9f37b8
--- /dev/null
@@ -0,0 +1,20 @@
+mainmodule simple_rput {
+
+  readonly CProxy_main mainProxy;
+
+  mainchare main {
+    entry main(CkArgMsg *m);
+    entry void maindone();
+  };
+
+  array [1D] Ping1 {
+    entry Ping1(int size);
+    entry void start();
+    entry void putSenderDone(CkDataMsg *m);
+    entry void putReceiverDone(CkDataMsg *m);
+    entry void recvNcpyInfo(CkNcpyDestination dest1, CkNcpyDestination dest2, CkNcpyDestination dest3);
+    entry void sendValidationData();
+    entry void validatePutData(int iArr2[size], double dArr2[size], char cArr2[size], int size);
+  };
+
+};
diff --git a/examples/charm++/zerocopy/entry_method_api/Makefile b/examples/charm++/zerocopy/entry_method_api/Makefile
new file mode 100644 (file)
index 0000000..4225c75
--- /dev/null
@@ -0,0 +1,16 @@
+DIRS   = pingpong simpleZeroCopy stencil3d
+
+all:
+       for d in $(DIRS); do \
+               ($(MAKE) -C $$d all OPTS='$(OPTS)' || exit 1) || exit 1; \
+       done
+
+test:
+       for d in $(DIRS); do \
+               ($(MAKE) -C $$d test OPTS='$(OPTS)' TESTOPTS='$(TESTOPTS)' || exit 1) || exit 1; \
+       done
+
+clean:
+       for d in $(DIRS); do ($(MAKE) -C $$d clean OPTS='$(OPTS)'); done
+       rm -f TAGS #*#
+       rm -f core *~
similarity index 84%
rename from examples/charm++/zerocopy/pingpong/Makefile
rename to examples/charm++/zerocopy/entry_method_api/pingpong/Makefile
index cf7e2a4b70e55b883f0625f87aef2210738b4a9f..23e468ae4535aa00da6a92b26e02e7e43a11bec9 100644 (file)
@@ -1,5 +1,5 @@
--include ../../../common.mk
-CHARMC=../../../../bin/charmc $(OPTS)
+-include ../../../../common.mk
+CHARMC=../../../../../bin/charmc $(OPTS)
 
 all:   pgm
 
similarity index 98%
rename from examples/charm++/zerocopy/pingpong/pingpong.C
rename to examples/charm++/zerocopy/entry_method_api/pingpong/pingpong.C
index ce280b69d5d0fba90961acfbf1d5ca08740271de..b90e06536e8570b5cf75e8036a9d00eea317648b 100644 (file)
@@ -1,9 +1,9 @@
 #include "pingpong.decl.h"
 
-#define BIG_ITER 1000
+#define BIG_ITER 10
 #define SMALL_ITER 100
 
-#define MAX_PAYLOAD 1 << 27
+#define MAX_PAYLOAD 1 << 12
 
 CProxy_main mainProxy;
 
similarity index 87%
rename from examples/charm++/zerocopy/simpleZeroCopy/Makefile
rename to examples/charm++/zerocopy/entry_method_api/simpleZeroCopy/Makefile
index 3bd2ab8a6f0dc20733839c662c8fefb9f1e33b92..28f08b07a61d2748da7ca6f131ea8e74a757dd8e 100644 (file)
@@ -1,5 +1,5 @@
--include ../../../common.mk
-CHARMC=../../../../bin/charmc $(OPTS)
+-include ../../../../common.mk
+CHARMC=../../../../../bin/charmc $(OPTS)
 
 all: simpleZeroCopy
 
similarity index 91%
rename from examples/charm++/zerocopy/stencil3d/Makefile
rename to examples/charm++/zerocopy/entry_method_api/stencil3d/Makefile
index e82590b0745e1ac2fd0f6f5c3c36d1a302d24545..b81102cf93f79d4b65bedb725fa26c6c88b0fe9f 100644 (file)
@@ -1,5 +1,5 @@
--include ../../../common.mk
-CHARMC = ../../../../bin/charmc $(OPTS)
+-include ../../../../common.mk
+CHARMC = ../../../../../bin/charmc $(OPTS)
 
 OBJS = stencil3d.o
 
similarity index 99%
rename from examples/charm++/zerocopy/stencil3d/stencil3d.C
rename to examples/charm++/zerocopy/entry_method_api/stencil3d/stencil3d.C
index 0fe0f05e5d838c00e30d8e085162c71ec10d1ef9..ac405af89bb79da408e94d9b17f9e2c4a02893cc 100644 (file)
@@ -203,9 +203,9 @@ class Stencil: public CBase_Stencil {
 
     Stencil(CkMigrateMessage* m) { }
 
-    ~Stencil() { 
-      delete [] temperature; 
-      delete [] new_temperature; 
+    ~Stencil() {
+      delete [] temperature;
+      delete [] new_temperature;
     }
 
     // Send ghost faces to the six neighbors
index 7e059e9f645781919fb4ce2b312c516b8e599f5a..2848bfb10c1560d119e3d387f07c96241635e5f5 100644 (file)
@@ -1,5 +1,9 @@
 ifneq ($(wildcard ../../../bin/.),)
        run = ../../../bin/testrun $(1) $(TESTOPTS)
 else
-       run = ../../../../bin/testrun $(1) $(TESTOPTS)
+       ifneq ($(wildcard ../../../../bin/.),)
+               run = ../../../../bin/testrun $(1) $(TESTOPTS)
+       else
+               run = ../../../../../bin/testrun $(1) $(TESTOPTS)
+       endif
 endif
index 81ec55c4783cf962d56a5c04d316e7e9f38212ac..edce3a6141e14b785e1ce5b28243bbb90087a58e 100644 (file)
@@ -5,12 +5,12 @@
 #include "charm++.h"
 #include "converse.h"
 
-#if CMK_ONESIDED_IMPL
 
 #if CMK_SMP && CMK_IMMEDIATE_MSG
 /*readonly*/ extern CProxy_ckcallback_group _ckcallbackgroup;
 #endif
 
+#if CMK_ONESIDED_IMPL
 /* Sender Functions */
 
 /*
@@ -315,3 +315,103 @@ int getRdmaBufSize(envelope *env){
 }
 
 #endif
+/* End of CMK_ONESIDED_IMPL */
+
+/* Support for Direct Nocopy API */
+
+// Ack handler function which invokes the callback
+void CkRdmaAckHandler(void *cbPtr, int pe, const void *ptr) {
+  CkCallback *cb = (CkCallback *)cbPtr;
+
+#if CMK_SMP && CMK_IMMEDIATE_MSG
+  //call to callbackgroup to call the callback when calling from comm thread
+  //this adds one more trip through the scheduler
+  _ckcallbackgroup[pe].call(*cb, sizeof(void *), (char*)&ptr);
+#else
+  //Invoke the destination callback
+  cb->send(sizeof(void *), (char *)&ptr);
+#endif
+}
+
+// Perform a nocopy put operation into the passed destination using this source
+void CkNcpySource::rput(CkNcpyDestination destination){
+  // Check that the count for both the counters matches
+  CkAssert(cnt <= destination.cnt);
+
+  // Check that this object is local when CkRput is called
+  CkAssert(CkNodeOf(pe) == CkMyNode());
+
+  if(CmiNodeOf(destination.pe) == CkMyNode()) {
+    // memcpy the data from the source buffer into the destination buffer
+    memcpy((void *)destination.ptr, ptr, cnt);
+
+    //Invoke the source callback
+    cb.send(sizeof(void *), &ptr);
+
+    //Invoke the destination callback
+    destination.cb.send(sizeof(void *), &destination.ptr);
+
+  } else {
+
+    // Issue the Rput call
+    CmiIssueRput(destination.ptr,
+                 &destination.layerInfo,
+                 &destination.cb,
+                 sizeof(CkCallback),
+                 destination.pe,
+                 ptr,
+                 &layerInfo,
+                 &cb,
+                 sizeof(CkCallback),
+                 CkMyPe(),
+                 cnt);
+  }
+}
+
+// Release the registered resources for this source object
+void CkNcpySource::releaseResource(){
+  CmiReleaseSourceResource(&layerInfo, pe);
+}
+
+// Perform a nocopy get operation into this destination using the passed source
+void CkNcpyDestination::rget(CkNcpySource source){
+
+  // Check that the count for both the counters matches
+  CkAssert(source.cnt <= cnt);
+
+  // Check that this object is local when CkRget is called
+  CkAssert(CkNodeOf(pe) == CkMyNode());
+
+  //Check if it is a within-process sending
+  if(CmiNodeOf(source.pe) == CkMyNode()) {
+
+    // memcpy the data from the source buffer into the destination buffer
+    memcpy((void *)ptr, source.ptr, cnt);
+
+    //Invoke the receiver's callback
+    cb.send(sizeof(void *), &ptr);
+
+    //Invoke the sender's callback
+    source.cb.send(sizeof(void *), &source.ptr);
+
+  } else {
+
+    // Issue the Rget call
+    CmiIssueRget(source.ptr,
+                 &source.layerInfo,
+                 &source.cb,
+                 sizeof(CkCallback),
+                 source.pe,
+                 ptr,
+                 &layerInfo,
+                 &cb,
+                 sizeof(CkCallback),
+                 CkMyPe(),
+                 cnt);
+  }
+}
+
+// Release the registered resources for this destination object
+void CkNcpyDestination::releaseResource(){
+  CmiReleaseDestinationResource(&layerInfo, pe);
+}
index 9fd34855ec6827d923ef2c2d9f5817400f3e895d..9a0ef3166b4f3ef6fb7aa6b4f999ae1215c63c33 100644 (file)
@@ -70,5 +70,88 @@ int getRdmaNumOps(envelope *env);
 //Get the sum of rdma buffer sizes using the metadata message
 int getRdmaBufSize(envelope *env);
 
+
+#endif /* End of CMK_ONESIDED_IMPL */
+
+
+/* Support for Nocopy Direct API */
+
+/* Use 0 sized headers for generic Direct API implementation */
+#ifndef CMK_NOCOPY_DIRECT_BYTES
+#define CMK_NOCOPY_DIRECT_BYTES 0
 #endif
+
+// Ack handler function which invokes the callbacks on the source and destination PEs
+void CkRdmaAckHandler(void *cookie);
+void CkRdmaAckHandler(void *cbPtr, int pe, const void *ptr);
+
+class CkNcpyDestination;
+
+// Class to represent an RDMA source
+class CkNcpySource{
+  public:
+  // pointer to the source buffer
+  const void *ptr;
+
+  // number of bytes
+  size_t cnt;
+
+  // callback to be invoked on the sender
+  CkCallback cb;
+
+  // home pe
+  int pe;
+
+  // machine specific information about the source pointer
+  char layerInfo[CMK_NOCOPY_DIRECT_BYTES];
+
+  CkNcpySource() : ptr(NULL), pe(-1) {}
+
+  CkNcpySource(const void *ptr_, size_t cnt_, CkCallback cb_) : ptr(ptr_), cnt(cnt_), cb(cb_){
+    pe = CkMyPe();
+    // set the source pointer layerInfo
+    CmiSetRdmaSrcInfo(&layerInfo, ptr, cnt);
+  }
+
+  void rput(CkNcpyDestination destination);
+
+  void releaseResource();
+};
+PUPbytes(CkNcpySource);
+
+// Class to represent an RDMA destination
+class CkNcpyDestination{
+  public:
+  // pointer to the destination buffer
+  const void *ptr;
+
+  // number of bytes
+  size_t cnt;
+
+  // callback to be invoked on the receiver
+  CkCallback cb;
+
+  // home pe
+  int pe;
+
+  // machine specific information about the destination pointer
+  char layerInfo[CMK_NOCOPY_DIRECT_BYTES];
+
+  CkNcpyDestination() : ptr(NULL), pe(-1) {}
+
+  CkNcpyDestination(const void *ptr_, size_t cnt_, CkCallback cb_) : ptr(ptr_), cnt(cnt_), cb(cb_) {
+    pe = CkMyPe();
+
+    // set the destination pointer layerInfo
+    CmiSetRdmaDestInfo(&layerInfo, ptr, cnt);
+  }
+
+  void rget(CkNcpySource source);
+
+  void releaseResource();
+};
+PUPbytes(CkNcpyDestination);
+
+
+
 #endif
index e14969bf69e0bd5671d2c98565655b9208c257be..808abd1271558e9d1d83348ec52cca1235204710 100644 (file)
@@ -66,6 +66,7 @@ never be excluded...
 #include "ckcheckpoint.h"
 #include "ck.h"
 #include "trace.h"
+#include "ckrdma.h"
 #include "CkCheckpoint.decl.h"
 #include "ckmulticast.h"
 #include <sstream>
@@ -1202,6 +1203,9 @@ void _initCharm(int unused_argc, char **argv)
     CkpvAccess(envelopeEventID) = 0;
        CkMessageWatcherInit(argv,CkpvAccess(_coreState));
        
+       // Set the ack handler function used for the direct nocopy api
+       CmiSetRdmaNcpyAck(CkRdmaAckHandler);
+
        /**
          The rank-0 processor of each node calls the 
          translator-generated "_register" routines. 
diff --git a/src/conv-core/conv-rdma.c b/src/conv-core/conv-rdma.c
new file mode 100644 (file)
index 0000000..70631cf
--- /dev/null
@@ -0,0 +1,147 @@
+/* Support for Direct Nocopy API (Generic Implementation)
+ * Specific implementations are in arch/layer/machine-onesided.{h,c}
+ */
+#include "converse.h"
+#if !CMK_ONESIDED_DIRECT_IMPL
+/* Support for generic implementation */
+
+// Function Pointer to Acknowledement handler function for the Direct API
+RdmaSingleAckCallerFn ncpyAckHandlerFn;
+
+// An Rget initiator PE sends this message to the target PE that will be the source of the data
+typedef struct _getRequestMsg {
+  char cmicore[CmiMsgHeaderSizeBytes];
+  int srcPe; /* Source processor */
+  int destPe; /* Destination processor */
+  int size; /* size of the source buffer */
+  char *srcAddr; /* Source Address */
+  char *destAddr; /* Destination Address */
+  int ackSize;  /* Number of bytes occupied by the ack */
+} getRequestMsg;
+
+// This is a header for RDMA payloads transferred as normal converse messages,
+// delivered to the PE holding the destination buffer (Rget initiator or Rput target)
+typedef struct _rdmaPayloadMsg {
+  char cmicore[CmiMsgHeaderSizeBytes];
+  int pe; /* Source processor */
+  int size; /* size of the buffer */
+  char *destAddr; /* Destination Address */
+  char *ref; /* Reference Address used for invoking acks*/
+} rdmaPayloadMsg;
+
+static int get_request_handler_idx;
+static int put_data_handler_idx;
+
+// Invoked when this PE has to send a large array for an Rget
+static void getRequestHandler(getRequestMsg *reqMsg){
+  void *srcAck = (char *)reqMsg + sizeof(getRequestMsg);
+  void *destAck = (char *)srcAck + reqMsg->ackSize;
+  // Get is implemented internally using a call to Put
+  CmiIssueRput(reqMsg->destAddr,
+               NULL,
+               destAck,
+               reqMsg->ackSize,
+               reqMsg->destPe,
+               reqMsg->srcAddr,
+               NULL,
+               srcAck,
+               reqMsg->ackSize,
+               reqMsg->srcPe,
+               reqMsg->size);
+}
+
+// Invoked when this PE receives a large array as the target of an Rput or the initiator of an Rget
+static void putDataHandler(rdmaPayloadMsg *recvMsg) {
+  // copy the received messsage into the user's destination address
+  memcpy(recvMsg->destAddr, (char *)recvMsg + sizeof(rdmaPayloadMsg), recvMsg->size);
+
+  // Invoke the destination ack
+  void *destAck = (char *)recvMsg + sizeof(rdmaPayloadMsg) + recvMsg->size;
+  ncpyAckHandlerFn(destAck, recvMsg->pe, recvMsg->destAddr);
+}
+
+// Rget/Rput operations are implemented as normal converse messages
+// This method is invoked during converse initialization to initialize these message handlers
+void CmiOnesidedDirectInit(void) {
+  get_request_handler_idx = CmiRegisterHandler((CmiHandler)getRequestHandler);
+  put_data_handler_idx = CmiRegisterHandler((CmiHandler)putDataHandler);
+}
+
+void CmiSetRdmaNcpyAck(RdmaSingleAckCallerFn fn) {
+  ncpyAckHandlerFn = fn;
+}
+
+void CmiIssueRget(
+  const void* srcAddr,
+  void *srcInfo,
+  void *srcAck,
+  int srcAckSize,
+  int srcPe,
+  const void* destAddr,
+  void *destInfo,
+  void *destAck,
+  int destAckSize,
+  int destPe,
+  int size) {
+
+  // Send a getRequestMsg to other PE requesting it to send the array
+  getRequestMsg *getReqMsg = (getRequestMsg *)CmiAlloc(sizeof(getRequestMsg) + srcAckSize + destAckSize);
+  getReqMsg->srcPe = srcPe;
+  getReqMsg->destPe = destPe;
+  getReqMsg->size = size;
+  getReqMsg->srcAddr = (char *)srcAddr;
+  getReqMsg->destAddr = (char *)destAddr;
+
+  CmiAssert(srcAckSize == destAckSize);
+  getReqMsg->ackSize = srcAckSize;
+
+  // copy the source ack into the getReqMsg
+  memcpy((char *)getReqMsg + sizeof(getRequestMsg), srcAck, srcAckSize);
+
+  // copy the destination ack into the getReqMsg
+  memcpy((char *)getReqMsg + sizeof(getRequestMsg) + srcAckSize, destAck, destAckSize);
+
+  CmiSetHandler(getReqMsg, get_request_handler_idx);
+  CmiSyncSendAndFree(srcPe, sizeof(getRequestMsg) + srcAckSize + destAckSize, getReqMsg);
+}
+
+void CmiIssueRput(
+  const void* destAddr,
+  void *destInfo,
+  void *destAck,
+  int destAckSize,
+  int destPe,
+  const void* srcAddr,
+  void *srcInfo,
+  void *srcAck,
+  int srcAckSize,
+  int srcPe,
+  int size) {
+
+  // Send a rdmaPayloadMsg to the other PE sending the array
+  rdmaPayloadMsg *recvMsg = (rdmaPayloadMsg *)CmiAlloc(sizeof(rdmaPayloadMsg) + size + destAckSize);
+
+  // copy the large array into the recvMsg
+  memcpy((char *)recvMsg + sizeof(rdmaPayloadMsg), srcAddr, size);
+
+  // copy the destination ack into the recvMsg
+  memcpy((char *)recvMsg + sizeof(rdmaPayloadMsg) + size, destAck, destAckSize);
+
+  // Invoke the source ack
+  ncpyAckHandlerFn(srcAck, srcPe, srcAddr);
+
+  recvMsg->pe = destPe;
+  recvMsg->size = size;
+  recvMsg->destAddr = (char *)destAddr;
+
+  CmiSetHandler(recvMsg, put_data_handler_idx);
+  CmiSyncSendAndFree(destPe, sizeof(rdmaPayloadMsg) + size + destAckSize, recvMsg);
+}
+
+// Dummy method declarations for API consistency
+void CmiSetRdmaSrcInfo(void *info, const void *ptr, int size) {}
+void CmiSetRdmaDestInfo(void *info, const void *ptr, int size) {}
+
+void CmiReleaseSourceResource(void *info, int pe) {}
+void CmiReleaseDestinationResource(void *info, int pe) {}
+#endif
index fed0716aaa7232faa9059e9d62164f757ae3ec61..f799909e32cc2b47a1e82e90f027704a74f4e016 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _CONV_RDMA_H
 #define _CONV_RDMA_H
 
+typedef void (*RdmaSingleAckCallerFn)(void *cbPtr, int pe, const void *ptr);
 typedef void (*RdmaAckCallerFn)(void *token);
 
 void *CmiSetRdmaAck(RdmaAckCallerFn fn, void *token);
@@ -17,4 +18,54 @@ int CmiGetRdmaGenRecvInfoSize(void);
 int CmiGetRdmaRecvInfoSize(int numOps);
 
 void CmiIssueRgets(void *recv, int pe);
+
+/* Support for Direct API */
+void CmiSetRdmaSrcInfo(void *info, const void *ptr, int size);
+void CmiSetRdmaDestInfo(void *info, const void *ptr, int size);
+void CmiSetRdmaNcpyAck(RdmaSingleAckCallerFn fn);
+
+/* CmiIssueRget initiates an RDMA read operation, transferring 'size' bytes of data from the address space of 'srcPe' to local address, 'destAddr'.
+ * When the runtime invokes srcAck on the source (target), it indicates safety to overwrite or free the srcAddr buffer.
+ * When the runtime invokes destAck on the destination (initiator), it indicates that the data has been successfully received in the
+ * destAddr buffer.
+ */
+void CmiIssueRget(
+  const void* srcAddr,
+  void *srcInfo,
+  void *srcAck,
+  int srcAckSize,
+  int srcPe,
+  const void* destAddr,
+  void *destInfo,
+  void *destAck,
+  int destAckSize,
+  int destPe,
+  int size);
+
+/* CmiIssueRput initiates an RDMA write operation, transferring 'size' bytes of data from the local address, 'srcAddr' to the address space of 'destPe'.
+ * When the runtime invokes srcAck on the source (initiator), it indicates safety to overwrite or free the srcAddr buffer.
+ * When the runtime invokes destAck on the destination (target), it indicates that the data has been successfully received in the
+ * destAddr buffer.
+ */
+
+void CmiIssueRput(
+  const void* destAddr,
+  void *destInfo,
+  void *destAck,
+  int destAckSize,
+  int destPe,
+  const void* srcAddr,
+  void *srcInfo,
+  void *srcAck,
+  int srcAckSize,
+  int srcPe,
+  int size);
+
+void CmiReleaseSourceResource(void *info, int pe);
+void CmiReleaseDestinationResource(void *info, int pe);
+
+#if !CMK_ONESIDED_DIRECT_IMPL
+// Function declaration used for the generic implementation of the Nocopy Direct API
+void CmiOnesidedDirectInit(void);
+#endif
 #endif
index 52cfe1d2803ff3829c61afa47ec9d36dc13311c1..62e0a09634212b84beb08d68ca6d3a93e51f8a88 100644 (file)
@@ -3764,6 +3764,10 @@ void ConverseCommonInit(char **argv)
 
   CmiPersistentInit();
   CmiIsomallocInit(argv);
+#if !CMK_ONESIDED_DIRECT_IMPL
+  // Initialize converse handlers for supporting generic Direct Nocopy API
+  CmiOnesidedDirectInit();
+#endif
   CmiDeliversInit();
   CsdInit(argv);
 #if CMK_CCS_AVAILABLE
index c87a953c7a3eccaf4c351c2e610de4e695b2fc99..1dc57b2eb34fe7db6726583835bee94f4aa8e472 100644 (file)
@@ -431,7 +431,7 @@ LIBCONV_CORE=convcore.o conv-conds.o conv-taskQ.o queueing.o msgmgr.o \
        converseProjections.o machineProjections.o \
        quiescence.o isomalloc.o mem-arena.o conv-counter.o memory-darwin-clang.o \
        global-nop.o cmipool.o cpuaffinity.o cputopology.o  \
-       cmitls.o memoryaffinity.o commitid.o sdag.o conv-interoperate.o
+       cmitls.o memoryaffinity.o commitid.o sdag.o conv-interoperate.o conv-rdma.o
 
 LIBCONV_LDB = topology.o generate.o edgelist.o