Updated and expanded Rashmi's changes for modern tcharm.
authorOrion Lawlor <olawlor@acm.org>
Mon, 21 Apr 2003 16:05:49 +0000 (16:05 +0000)
committerOrion Lawlor <olawlor@acm.org>
Mon, 21 Apr 2003 16:05:49 +0000 (16:05 +0000)
doc/tcharm/manual.tex

index 83812b5ab630ba7b22da3be985a8dd9c689221a5..a69409ed816cf657a89d60dcc8644dad1ad8d320 100644 (file)
@@ -559,75 +559,86 @@ 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 writing a library that uses TCharm.
+overview of how to go about writing a library in Charm++ that uses TCharm.
 
-The overall scheme for writing a TCharm-based library "Foo" is
+Using TCharm with your library automatically provides your users with a 
+clean C/F90 API (described in the preceeding chapters) for basic memory 
+managment, I/O, and migration.  It also allows you to use a convenient
+"thread->suspend()" and "thread->resume()" API for blocking a thread,
+which works properly with the load balancer, unlike CthSuspend/CthAwaken.
+
+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,
+\item Decide how to do a one-time startup initialization.  If the user
+is combining multiple frameworks, you just have to provide a FOO\_Attach
+routine that creates a new array of your objects---the user will call this
+from their TCHARM\_User\_setup routine.  But if the user's only library is 
+Foo, and they don't write a TCHARM\_User\_setup routine, you'd like the 
+thread creation and FOO\_Attach to happen automatically.  The canonical way to do 
+this is to register a \kw{FallbackSetup} routine from an initcall routine. 
+This routine is used if the user doesn't provide a TCHARM\_User\_setup routine,
+and it normally 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
+void fooDriver(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)
+static void fooFallbackSetup(void)
 \{
   //creates the TCharm threads and attaches client's routine to them
-  TCharmCreate(TCharmGetNumChunks(), fooStart);
+  TCHARM\_Create(TCHARM\_Get_num_chunks(), fooDriver);
   //Could call some user routine here to do some startup work
-  Foo\_Attach();
+  FOO\_Attach();
 \}
 
-void FooInit(void)
+/*initcall*/ void fooNodeInit(void)
 \{
-  //initialize thread private variable her, mentioned later.
+  //initialize thread private variable here, mentioned later.
   .......
-  TCharmSetFallbackSetup(FooFallbackSetup);
+  TCHARM\_Set\_fallback\_setup(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()
+\item Create your array and attach it to the TCharm threads using
+TCHARM\_Attach\_start and TCHARM\_Attach\_finish. The user's main 
+parallel routine (fooDriver, or whatever thread routine was registered) 
+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)
+//directly from TCHARM\_User\_setup (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 threadsAID; int nchunks;
+  CkArrayOptions opts=TCHARM\_Attach\_start(&threadsAID,&nchunks);
+  
+  //actually create your library array here (FooChunk in this case)
   CkArrayID aid = CProxy\_FooChunk::ckNew(opt);
-  tc->addClient(aid);
+  TCHARM\_Attach\_finish(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.
+This is to regain context when you are 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()
+//routines called from fooDriver()
 CtvStaticDeclare(FooChunk *, \_fooptr);
 
 /* The following routine is listed as an initcall in the .ci file */
-void FooInit(void)
+/*initcall*/ void fooNodeInit(void)
 \{
   CtvInitialize(FooChunk*, \_fooptr);
-  TCharmSetFallbackSetup(FooFallbackSetup);
+  TCHARM\_Set\_fallback\_setup(fooFallbackSetup);
 \}
 \end{alltt}
 
@@ -663,6 +674,7 @@ protected:
 \}
 \end{alltt}
 
+
 \item Block a thread for communication using thread->suspend and
 thread->resume
 
@@ -683,11 +695,28 @@ void FooChunk::recvReply(someReplyMsg *m)
 \}
 \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.
+these disable isomalloc allocation. 
+
+The charm-api.h macros CDECL, FDECL and
+FTN\_NAME should be used to provide both C and FORTRAN versions of each 
+API call.  You should use the "MPI capitalization standard", where the library
+name is all caps, followed by a capitalized first word, with all subsequent 
+words lowercase, separated by underscores.  This capitalization system is 
+consistent, and works well with case-insensitive languages like Fortran.
+
+Fortran parameter passing is a bit of an art, but basically for simple 
+types like int (INTEGER in fortran), float (SINGLE PRECISION or REAL*4),
+and double (DOUBLE PRECISION or REAL*8), things work well.  Single parameters
+are always passed via pointer in Fortran, as are arrays.  Even though 
+Fortran indexes arrays based at 1, it will pass you a pointer to the 
+first element, so you can use the regular C indexing.  The only time Fortran
+indexing need be considered is when the user passes you an index--the
+int index will need to be decremented before use, or incremented before
+a return.
 
 \begin{alltt}
 CDECL void FOO\_Communicate(int x, double y, int * arr) \{
@@ -697,10 +726,10 @@ CDECL void FOO\_Communicate(int x, double y, int * arr) \{
 \}
 
 //In fortran, everything is passed via pointers
-FDECL void FTN\_NAME(FOOCOMMUNICATE, foocommunicate)
+FDECL void FTN\_NAME(FOO_COMMUNICATE, foo_communicate)
      (int *x, double *y, int *arr)
 \{
-   TCHARM\_API\_TRACE("FOOCOOMMUNICATE", "foo");
+   TCHARM\_API\_TRACE("FOO_COMMUNICATE", "foo");
    FooChunk *f = CtvAccess(\_fooptr);
    f->doCommunicate(*x, *y, arr); 
 \}