*** empty log message ***
authorJosh Yelon <jyelon@uiuc.edu>
Mon, 2 Mar 1998 18:12:24 +0000 (18:12 +0000)
committerJosh Yelon <jyelon@uiuc.edu>
Mon, 2 Mar 1998 18:12:24 +0000 (18:12 +0000)
src/conv-ldb/cldb.c [new file with mode: 0644]
src/conv-ldb/cldb.rand.c [new file with mode: 0644]

diff --git a/src/conv-ldb/cldb.c b/src/conv-ldb/cldb.c
new file mode 100644 (file)
index 0000000..e91269e
--- /dev/null
@@ -0,0 +1,71 @@
+#include "converse.h"
+/*
+ * How to write a load-balancer:
+ *
+ * 1. Every load-balancer must contain a definition of struct CldField.
+ *    This structure describes what kind of data will be piggybacked on
+ *    the messages that go through the load balancer.  The structure
+ *    must include certain predefined fields.  Put the word
+ *    CLD_STANDARD_FIELD_STUFF at the front of the struct definition
+ *    to include these predefined fields.
+ *
+ * 2. Every load-balancer must contain a definition of the global variable
+ *    Cld_fieldsize.  You must initialize this to sizeof(struct CldField).
+ *    This is not a CPV or CSV variable, it's a plain old C global.
+ *
+ * 3. When you send a message, you'll probably want to temporarily
+ *    switch the handler.  The following function will switch the handler
+ *    while saving the old one:
+ *
+ *       CldSwitchHandler(msg, field, newhandler);
+ *
+ *    Field must be a pointer to the gap in the message where the CldField
+ *    is to be stored.  The switch routine will use this region to store
+ *    the old handler, as well as some other stuff.  When the message
+ *    gets handled, you can switch the handler back like this:
+ *    
+ *       CldRestoreHandler(msg, &field);
+ *
+ *    This will not only restore the handler, it will also tell you
+ *    where in the message the CldField was stored.
+ *
+ * 4. Don't forget that CldEnqueue must support directed transmission of
+ *    messages as well as undirected, and broadcasts too.
+ *
+ */
+
+int CldRegisterInfoFn(CldInfoFn fn)
+{
+  return CmiRegisterHandler((CmiHandler)fn);
+}
+
+int CldRegisterPackFn(CldPackFn fn)
+{
+  return CmiRegisterHandler((CmiHandler)fn);
+}
+
+/*
+ * These next subroutines are balanced on a thin wire.  They're
+ * correct, but the slightest disturbance in the offsets could break them.
+ *
+ */
+
+void CldSwitchHandler(char *cmsg, int *field, int handler)
+{
+  int *data = (int*)(cmsg+CmiMsgHeaderSizeBytes);
+  field[1] = CmiGetHandler(cmsg);
+  field[0] = data[0];
+  data[0] = ((char*)field)-cmsg;
+  CmiSetHandler(cmsg, handler);
+}
+
+void CldRestoreHandler(char *cmsg, void *hfield)
+{
+  int *data = (int*)(cmsg+CmiMsgHeaderSizeBytes);
+  int offs = data[0];
+  int *field = (int*)(cmsg+offs);
+  data[0] = field[0];
+  CmiSetHandler(cmsg, field[1]);
+  *(int**)hfield = field;
+}
+
diff --git a/src/conv-ldb/cldb.rand.c b/src/conv-ldb/cldb.rand.c
new file mode 100644 (file)
index 0000000..c763d27
--- /dev/null
@@ -0,0 +1,105 @@
+#include "converse.h"
+
+/* CldEnqueue is the load balancer.  It accepts a message, and
+ * enqueues the message on some processor of its own choosing.
+ * Processors are chosen in such a way as to help distribute the
+ * workload.
+ *
+ * The user of the load balancer must set aside some space in the
+ * message for load balancer to store temporary data.  The number of
+ * bytes that must be reserved is CLD_FIELDSIZE.  There is no
+ * stipulation about where in the message this field must be.
+ *
+ * If the message is to be prioritized, then the message must also
+ * contain its priority.  This can be omitted if the message is to
+ * have the null priority.  There is no stipulation about where in
+ * the message the priority must be stored.
+ *
+ * The user of the load balancer must write an "info" function.
+ * The load-balancer will call the info function when it needs to
+ * know any of the following pieces of information:
+ *
+ *    - the length of the message, in bytes.
+ *    - the queueing strategy of the message.
+ *    - where the priority is, in the message.
+ *    - where the ldb field is, in the message.
+ *
+ * The info function must be able to determine all this information.
+ * The info function must be registered, much like a converse handler,
+ * using CldRegisterInfoFn.  It must have this prototype:
+ *
+ *    void Info(void *msg, 
+ *              int *len,
+ *              void *ldbfield,
+ *              int *queuing,
+ *              int *priobits,
+ *              int **prioptr);
+ *
+ * The user of the load balancer must also write a "pack" function.
+ * When the load balancer is about to send the message across
+ * processor boundaries, it will call the pack function.  The
+ * pack function may modify the message in any way.  The pack function
+ * must be registered using CldRegisterPackFn, and must have this
+ * prototype:
+ *
+ *    void Pack(void **msg);
+ *
+ * Normally, CldEnqueue is used for load-balancing.  It can also be
+ * used as a convenience that helps you enqueue a message on a processor
+ * of your choosing.  The parameter 'pe' lets you specify which processor
+ * the message is to go to.  If the value CLD_ANYWHERE is given, then
+ * the message is load-balanced.  If it is CLD_BROADCAST, the message
+ * is broadcast to all other processors.  If it is CLD_BROADCAST_ALL,
+ * the message is broadcast to all processors.  If it is a processor
+ * number, the message is sent to a specific location.
+ *
+ */
+
+typedef struct CldField
+{
+  CLD_STANDARD_FIELD_STUFF
+  int infofn;
+}
+*CldField;
+
+int Cld_fieldsize = sizeof(struct CldField);
+
+void CldHandler(char *msg)
+{
+  int len, queueing, priobits; CldField ldbfield;
+  unsigned int *prioptr; CldInfoFn ifn;
+  CmiGrabBuffer(&msg);
+  CldRestoreHandler(msg, &ldbfield);
+  ifn = (CldInfoFn)CmiHandlerToFunction(ldbfield->infofn);
+  ifn(msg, &len, &ldbfield, &queueing, &priobits, &prioptr);
+  CsdEnqueueGeneral(msg, queueing, priobits, prioptr);
+}
+
+CpvDeclare(int, CldHandlerIndex);
+
+void CldEnqueue(int pe, void *msg, int infofn, int packfn)
+{
+  int len, queueing, priobits; unsigned int *prioptr; CldField ldbfield;
+  CldInfoFn ifn = (CldInfoFn)CmiHandlerToFunction(infofn);
+  CldPackFn pfn = (CldPackFn)CmiHandlerToFunction(packfn);
+  if (CmiGetHandler(msg) >= CpvAccess(CmiHandlerMax)) *((int*)0)=0;
+  if (pe == CLD_ANYWHERE) pe = ((rand()&0x7FFFFFFF)%CmiNumPes());
+  if (pe == CmiMyPe()) {
+    ifn(msg, &len, &ldbfield, &queueing, &priobits, &prioptr);
+    CsdEnqueueGeneral(msg, queueing, priobits, prioptr);
+  } else {
+    pfn(&msg);
+    ifn(msg, &len, &ldbfield, &queueing, &priobits, &prioptr);
+    CldSwitchHandler(msg, ldbfield, CpvAccess(CldHandlerIndex));
+    ldbfield->infofn = infofn;
+    if (pe==CLD_BROADCAST) CmiSyncBroadcastAndFree(len, msg);
+    else if (pe==CLD_BROADCAST_ALL) CmiSyncBroadcastAllAndFree(len, msg);
+    else CmiSyncSendAndFree(pe, len, msg);
+  }
+}
+
+void CldModuleInit()
+{
+  CpvInitialize(int, CldHandlerIndex);
+  CpvAccess(CldHandlerIndex) = CmiRegisterHandler(CldHandler);
+}