library instrns
authorRashmi Jyothi <jyothi@uiuc.edu>
Tue, 15 Apr 2003 12:36:22 +0000 (12:36 +0000)
committerRashmi Jyothi <jyothi@uiuc.edu>
Tue, 15 Apr 2003 12:36:22 +0000 (12:36 +0000)
doc/tcharm/manual.tex

index d4387357f940f965d6348eff11db957477e3cbaa..3729efea8799fd8ebfe89fa9aa0da5f91b9a65c1 100644 (file)
@@ -93,7 +93,7 @@ To see why this is a problem, consider a program fragment like:
 \end{alltt}
 
 After this code executes, we might expect \uw{b} to always be equal to \uw{a}.
-But if \uw{foo} is a global variable, \kw{MPI\_Recv} may block and 
+but if \uw{foo} is a global variable, \kw{MPI\_Recv} may block and 
 \uw{foo} could be changed by another thread.
 
 For example, if two threads execute this program, they could interleave like:
@@ -559,6 +559,154 @@ available if \charmpp{} was compiled with CMK\_OPTIMIZE.
 
 \end{description}
 
+\section{Writing a library using TCharm}
+\label{sec:tlib}
+
+Until now, things were presented from a client's (one who writes a program that
+depends on a library written using TCharm) perspective. This section gives an
+overview of how to go about writinfg a library that uses TCharm.
+
+The overall scheme for writing a TCharm-based library "Foo" is
+
+\begin{itemize}
+\item Decide how to do a one-time startup initialization. The canonical way to do 
+this is to register a \kw{FallbackSetup} routine from an initcall routine. This 
+routine creates the TCharm threads and attaches the library code to them. For 
+instance,
+
+\begin{alltt}
+void fooStart(void); //Client implements this routine to carry out the parallel work
+
+//Startup routine to if the user does not define their own
+static void FooFallbackSetup(void)
+{
+  //creates the TCharm threads and attaches client's routine to them
+  TCharmCreate(TCharmGetNumChunks(), fooStart);
+  //Could call some user routine here to do some startup work
+  Foo\_Attach();
+}
+
+void FooInit(void)
+{
+  //initialize thread private variable her, mentioned later.
+  .......
+  TCharmSetFallbackSetup(FooFallbackSetup);
+}
+\end{alltt}
+
+\item Create your array and attach it to the TCharm threads. The user's main 
+parallel routine will start as soon as you call thread->ready()
+
+\begin{alltt}
+//This is either called by FooFallbackSetuo mentioned above, or by the user
+//directly (for multi-module programs)
+void Foo\_Attach(void)
+{
+  TCharmSetupcookie * tc = TCharmSetupCookie::get();
+  CkArrayOptions opt(tc->getNumElements());
+  if (!tc->hasThreads())
+     CkAbort("You must create a threads array with TCharmCreate"
+              "before calling Foo\_Attach!\\n" );
+  opt.bindTo(tc->getThreads());
+
+  //actually create the library array here (FooChunk in this case)
+  CkArrayID aid = CProxy\_FooChunk::ckNew(opt);
+  tc->addClient(aid);
+}
+\end{alltt}
+
+\item Set up a thread-private variable(Ctv) to point to the library object. 
+This is to regain contect once, called by the user.
+
+\begin{alltt}
+//\_fooptr is the Ctv that points to the current chunk FooChunk and is only valid in 
+//routines called from fooStart()
+CtvStaticDeclare(FooChunk *, \_fooptr);
+
+/* The following routine is listed as an initcall in the .ci file */
+void FooInit(void)
+{
+  CtvInitialize(FooChunk*, \_fooptr);
+  TCharmSetFallbackSetup(FooFallbackSetup);
+}
+\end{alltt}
+
+\item Define the array used by the library
+
+\begin{alltt}
+class FooChunk: public TCharmClient1D {
+   CProxy\_FooChunk thisProxy;
+protected:
+   //called by TCharmClient1D when thread changes
+   virtual void setupThreadPrivate(CthThread forThread)
+   {
+      CtvAccessOther(forThread, \_fooptr) = this;
+   }
+   
+   FooChunk(CkArrayID aid):TCharmClient1D(aid)
+   {
+      thisProxy = this;
+      tCharmClientInit();
+      //add any other initialization here
+      thread->ready(); //starts parallel work  
+   }
+
+   virtual void pup(PUP::er &p) {
+     TCharmClient1D::pup(p);
+     //usual pup calls
+   }
+   
+   //other calls, defined later
+   int doCommunicate(...);
+   void recvReply(someReplyMsg *m);
+   ........
+}
+\end{alltt}
+
+\item Block a thread for communication using \kw{thread\_suspend} and
+\kw{thread\_resume}
+
+\begin{alltt}
+int FooChunk::doCommunicate(...)
+{
+   replyGoesHere = NULL;
+   thisProxy[destChunk].sendRequest(...);
+   thread->suspend(); //wait for reply to come back
+   return replyGoesHere->data;
+}
+
+void FooChunk::recvReply(someReplyMsg *m)
+{
+  if(replyGoesHere!=NULL) CkAbort("FooChunk: unexpected reply\\n");
+  replyGoesHere = m;
+  thread->resume(); //Got the reply -- start client again
+}
+\end{alltt}
+
+\item Add API calls. This is how user code running in the thread interacts
+with the newly created library. Calls to TCHARM\_API\_TRACE macro must be 
+added to the start of every user-callable method. In addition to tracing,
+these disable isomalloc allocation. charm-api.h macros v.i.z CDECL, FDECL and
+FTN\_NAME can be used to provide both C and FORTRAN versions of each API call.
+
+\begin{alltt}
+CDECL void FOO\_Communicate(int x, double y, int * arr) {
+   TCHARM\_API\_TRACE("FOO\_Communicate", "foo"); //2nd parameter is the name of the library
+   FooChunk *f = CtvAccess(\_fooptr);
+   f->doCommunicate(x, y, arr);
+}
+
+//In fortran, everything is passed via pointers
+FDECL void FTN\_NAME(FOOCOMMUNICATE, foocommunicate)
+     (int *x, double *y, int *arr)
+{
+   TCHARM\_API\_TRACE("FOOCOOMMUNICATE", "foo");
+   FooChunk *f = CtvAccess(\_fooptr);
+   f->doCommunicate(*x, *y, arr); 
+}
+\end{alltt}
+
+\end{itemize}
 
 \input{index}
 \end{document}