Silly double-word typo.
[charm.git] / doc / tcharm / manual.tex
1 \documentclass[10pt]{article}
2 \usepackage{../pplmanual}
3 \input{../pplmanual}
4
5 \newcommand{\tcharm}{\textsc{TCharm}}
6
7 \makeindex
8
9 \title{Threaded \charmpp Manual}
10 \version{1.0}
11 \credits{
12 The initial version of Threaded \charmpp{} was developed
13 in late 2001 by Orion Lawlor.
14 }
15
16 \begin{document}
17
18 \maketitle
19
20 \section{Motivation}
21
22 \charmpp{} includes several application frameworks, such as the 
23 Finite Element Framework, the Multiblock Framework, and AMPI.  
24 These frameworks do almost all their work in load balanced, 
25 migratable threads.  
26
27 The Threaded \charmpp{} Framework, \tcharm{}, provides both
28 common runtime support for these threads and facilities for
29 combining multiple frameworks within a single program.
30 For example, you can use \tcharm{} to create a Finite Element
31 Framework application that also uses AMPI to communicate between
32 Finite Element chunks.
33
34 Specifically, \tcharm{} provides language-neutral interfaces for:
35 \begin{enumerate}
36 \item{Program startup, including read-only global data setup and the
37 configuration of multiple frameworks.}
38 \item{Run-time load balancing, including migration.}
39 \item{Program shutdown.}
40 \end{enumerate}
41
42 The first portion of this manual describes the general properties 
43 of \tcharm{} common to all the application frameworks, such as 
44 program contexts and how to write migratable code.
45 The second portion describes in detail how to combine separate 
46 frameworks into a single application.
47
48
49 \section{Basic \tcharm{} Programming}
50 Any routine in a \tcharm{} program runs in one of two contexts:
51
52 \begin{description}
53
54 \item[Serial Context] Routines that run on only one processor
55 and with only one set of data. There are absolutely
56 no limitations on what a serial context routine can do---it 
57 is as if the code were running in an ordinary serial program.
58 Startup and shutdown routines usually run in the serial context.
59
60 \item[Parallel Context] Routines that run on several processors,
61 and may run with several different sets of data on a single processor.
62 This kind of routine must obey certain restrictions.  The program's
63 main computation routines always run in the parallel context.
64
65 \end{description}
66
67 Parallel context routines run in a migratable, 
68 user-level thread maintained by \tcharm{}.  
69 Since there are normally several of these threads per processor,
70 any code that runs in the parallel context has to be thread-safe.
71 However, \tcharm{} 
72 is non-preemptive, so it will only switch threads when you make
73 a blocking call, like ``MPI\_Recv" or ``FEM\_Update\_Field".
74
75
76
77 \subsection{Global Variables}
78 \label{sec:global}
79 By ``global variables'', we mean anything that is stored at a fixed, 
80 preallocated location in memory.  In C, this means variables declared 
81 at file scope or with the \kw{static} keyword.  In Fortran, this is
82 variables that are part of a \kw{COMMON} block or declared inside 
83 a \kw{MODULE}.
84
85 Global variables are shared by all the threads on a processor, which
86 makes using global variables extremely error prone.
87 To see why this is a problem, consider a program fragment like:
88
89 \begin{alltt}
90   foo=a
91   call MPI_Recv(...)
92   b=foo
93 \end{alltt}
94
95 After this code executes, we might expect \uw{b} to always be equal to \uw{a}.
96 But if \uw{foo} is a global variable, \kw{MPI\_Recv} may block and 
97 \uw{foo} could be changed by another thread.
98
99 For example, if two threads execute this program, they could interleave like:
100
101 \vspace{0.1in}
102 \begin{tabular}{|l|l|}\hline
103 \em{Thread 1} & \em{Thread 2}\\
104 \hline
105 \uw{foo}=1 & \\
106 block in MPI\_Recv & \\
107  & \uw{foo}=2 \\
108  & block in MPI\_Recv \\
109 \uw{b}=\uw{foo} & \\
110 \hline\end{tabular}
111 \vspace{0.1in}
112
113 At this point, thread 1 might expect \uw{b} to be 1; but it will actually be 2.
114 From the point of view of thread 1, the global variable \uw{foo} suddenly
115 changed its value during the call to \kw{MPI\_Recv}.
116
117 There are several possible solutions to this problem:
118
119 \begin{itemize}
120 \item Never use global variables---only use parameters or local variables.  
121 This is the safest and most general solution.
122 One standard practice is to collect all the globals into a C struct or 
123 Fortran type named ``Globals", and pass a pointer to this object to all
124 your subroutines.  This also combines well with the pup method for doing
125 migration-based load balancing, as described in Section~\ref{sec:pup}.
126
127 \item Never write {\em different} values to global variables.  If every thread
128 writes the same value, global variables can be used safely.  For example,
129 you might store some parameters read from a configuration file like the 
130 simulation timestep $\Delta t$.  See Section~\ref{sec:readonlyglobal}
131 for another, more convenient way to set such variables.
132
133 \item Never issue a blocking call while your global variables are set.
134 This will not work on a SMP version of Charm++, where several processors
135 may share a single set of global variables.
136 Even on a non-SMP version, this is a dangerous solution, because someday 
137 someone might add a blocking call while the variables are set.  
138 This is only a reasonable solution when calling legacy code or 
139 using old serial libraries that might use global variables.
140 \end{itemize}
141
142 The above only applies to routines that run in the parallel context.
143 There are no restrictions on global variables for serial context
144 code.
145
146
147
148 \subsection{Input/Output}
149 \label{sec:io}
150
151 In the parallel context, there are several limitations on open
152 files.  First, several threads may run on one processor, so
153 Fortran Logical Unit Numbers are shared by all the threads on
154 a processor.  Second, open files are left behind when a thread 
155 migrates to another processor---it is a crashing error to open a 
156 file, migrate, then try to read from the file.
157
158 Because of these restrictions, it is best to open files only when
159 needed, and close them as soon as possible.  In particular, it
160 is best if there are no open files whenever you make blocking calls.
161
162
163 \subsection{Migration-Based Load Balancing}
164 \label{sec:migration}
165 \label{sec:isomalloc}
166
167 The \charmpp\ runtime framework includes an automatic run-time load balancer,
168 which can monitor the performance of your parallel program.
169 If needed, the load balancer can ``migrate'' threads from heavily-loaded
170 processors to more lightly-loaded processors, improving the load balance and
171 speeding up the program.  For this to be useful, you need to pass the 
172 link-time argument \kw{-balancer} \uw{B} to set the load balancing algorithm,
173 and the run-time argument \kw{+vp} \uw{N} (use \uw{N} virtual processors)
174 to set the number of threads.
175 The ideal number of threads per processor depends on the problem, but
176 we've found five to a hundred threads per processor to be a useful range.
177
178 When a thread migrates, all its data must be brought with it.
179 ``Stack data'', such as variables declared locally in a subroutine,
180 will be brought along with the thread automatically.  Global data,
181 as described in Section~\ref{sec:global}, is never brought with the thread
182 and should generally be avoided.
183
184 ``Heap data'' in C is structures and arrays allocated using \kw{malloc} or \kw{new};
185 in Fortran, heap data is TYPEs or arrays allocated using \kw{ALLOCATE}.
186 To bring heap data along with a migrating thread, you have two choices:
187 write a pup routine or use isomalloc.  Pup routines are described in 
188 Section~\ref{sec:pup}.
189
190 {\em Isomalloc} is a special mode which controls the allocation of heap data.  
191 You enable isomalloc allocation using the link-time flag ``-memory isomalloc''.  
192 With isomalloc, migration is completely transparent---all your allocated data 
193 is automatically brought to the new processor.  The data will be unpacked at the same
194 location (the same virtual addresses) as it was stored originally; so even
195 cross-linked data structures that contain pointers still work properly.
196
197 The limitations of isomalloc are:
198 \begin{itemize}
199 \item Wasted memory.  Isomalloc uses a special interface\footnote{
200 The interface used is \kw{mmap}.} to aquire memory, and the finest granularity
201 that can be aquired is one page, typically 4KB.  This means if you allocate
202 a 2-entry array, isomalloc will waste an entire 4KB page.  We should eventually 
203 be able to reduce this overhead for small allocations.
204
205 \item Limited space on 32-bit machines.  Machines where pointers are 32 bits
206 long can address just 4GB ($2^32$ bytes) of virtual address space.  Additionally, 
207 the operating system and conventional heap already use a significant amount 
208 of this space; so the total virtual address space available is typically under 1GB.  
209 With isomalloc, all processors share this space, so with just 20 processors
210 the amount of memory per processor is limited to under 50MB!  This is an 
211 inherent limitation of 32-bit machines; to run on more than a few processors you 
212 must use 64-bit machines or avoid isomalloc.
213 \end{itemize}
214
215
216
217 \section{Advanced \tcharm{} Programming}
218 The preceeding features are enough to write simple programs
219 that use \tcharm{}-based frameworks.  These more advanced techniques
220 provide the user with additional capabilities or flexibility.
221
222
223 \subsection{Writing a Pup Routine}
224 \label{sec:pup}
225
226 The runtime system can automatically move your thread stack to the new
227 processor, but unless you use isomalloc, you must write a pup routine to 
228 move any global or heap-allocated data to the new processor.  A pup
229 (Pack/UnPack) routine can perform both packing (converting your data into a
230 network message) and unpacking (converting the message back into your data).  
231 A pup routine is passed a pointer to your data block and a
232 special handle called a ``pupper'', which contains the network message.  
233
234 In a pup routine, you pass all your heap data to routines named \kw{pup\_}\uw{type} or \kw{fpup\_}\uw{type}, where
235 \uw{type} is either a basic type (such as int, char, float, or double) or an array
236 type (as before, but with a ``s'' suffix).  Depending on the direction of
237 packing, the pupper will either read from or write to the values you pass--
238 normally, you shouldn't even know which.  The only time you need to know the
239 direction is when you are leaving a processor, or just arriving.
240 Correspondingly, the pupper passed to you may be deleting (indicating that you
241 are leaving the processor, and should delete your heap storage after packing),
242 unpacking (indicating you've just arrived on a processor, and should allocate
243 your heap storage before unpacking), or neither (indicating the system is
244 merely sizing a buffer, or checkpointing your values).
245
246 pup functions are much easier to write than explain-- a simple C heap block
247 and the corresponding pup function is:
248
249 \begin{alltt}
250      typedef struct \{
251        int n1;/*Length of first array below*/
252        int n2;/*Length of second array below*/
253        double *arr1; /*Some doubles, allocated on the heap*/
254        int *arr2; /*Some ints, allocated on the heap*/
255      \} my_block;
256  
257      void pup_my_block(pup_er p,my_block *m)
258      \{
259        if (pup_isUnpacking(p)) \{ /*Arriving on new processor*/
260          m->arr1=malloc(m->n1*sizeof(double));
261          m->arr2=malloc(m->n2*sizeof(int));
262        \}
263        pup_doubles(p,m->arr1,m->n1);
264        pup_ints(p,m->arr2,m->n2);
265        if (pup_isDeleting(p)) \{ /*Leaving old processor*/
266          free(m->arr1);
267          free(m->arr2);
268        \}
269      \}
270 \end{alltt}
271
272 This single pup function can be used to copy the \kw{my\_block} data into a
273 message buffer and free the old heap storage (deleting pupper); allocate
274 storage on the new processor and copy the message data back (unpacking pupper);
275 or save the heap data for debugging or checkpointing.
276
277 A Fortran block TYPE and corresponding pup routine is as follows:
278
279 \begin{alltt}
280      MODULE my_block_mod
281        TYPE my_block
282          INTEGER :: n1,n2x,n2y
283          DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:) :: arr1
284          INTEGER, ALLOCATABLE, DIMENSION(:,:) :: arr2
285        END TYPE
286      END MODULE
287  
288      SUBROUTINE pup_my_block(p,m)
289        IMPLICIT NONE
290        USE my_block_mod
291        USE pupmod
292        INTEGER :: p
293        TYPE(my_block) :: m
294        IF (fpup_isUnpacking(p)) THEN
295          ALLOCATE(m%arr1(m%n1))
296          ALLOCATE(m%arr2(m%n2x,m%n2y))
297        END IF
298        call fpup_doubles(p,m%arr1,m%n1)
299        call fpup_ints(p,m%arr2,m%n2x*m%n2y)
300        IF (fpup_isDeleting(p)) THEN
301          DEALLOCATE(m%arr1)
302          DEALLOCATE(m%arr2)
303        END IF
304      END SUBROUTINE
305 \end{alltt}
306
307
308 You indicate to \tcharm{} that you want a pup routine called using
309 the routine below.  An arbitrary number of blocks can be registered
310 in this fashion.
311
312 \vspace{0.2in}
313 \function{void TCharmRegister(void *block, TCharmPupFn pup\_fn)}
314 \function{SUBROUTINE tcharm\_register(block,pup\_fn)}
315     \args{TYPE(varies), POINTER :: block}
316     \args{SUBROUTINE :: pup\_fn}
317
318      Associate the given data block and pup function.  Can only be
319      called from the parallel context.  For the declarations above, you call
320      \kw{TCharmRegister} as:
321
322 \begin{alltt}
323           /*In C/C++ driver() function*/
324           my_block m;
325           TCharmRegister(m,(TCharmPupFn)pup_my_block);
326  
327           !- In Fortran driver subroutine
328           use my_block_mod
329           interface
330             subroutine pup_my_block(p,m)
331               use my_block_mod
332               INTEGER :: p
333               TYPE(my_block) :: m
334             end subroutine
335           end interface
336           TYPE(my_block) :: m
337           call TCharmRegister(m,pup_my_block)
338 \end{alltt}
339
340      Note that the data block must be allocated on the stack.
341
342 \vspace{0.2in}
343 \function{void TCharmMigrate()}
344 \function{subroutine TCharmMigrate()}
345
346      Informs the load balancing system that you are ready to be
347      migrated, if needed.  If the system decides to migrate you, the
348      pup function passed to \kw{TCharm\_Register} will first be called with 
349      a sizing pupper, then a packing, deleting pupper.  Your stack and pupped
350      data will then be sent to the destination machine, where your pup
351      function will be called with an unpacking pupper.  \kw{TCharm\_Migrate}
352      will then return.  Can only be called from in the parallel context.
353
354
355
356 \subsection{Readonly Global Variables}
357 \label{sec:readonlyglobal}
358
359 You can also use a pup routine to set up initial values for global
360 variables on all processors.  This pup routine is called with only
361 a pup handle, just after the serial setup routine, and just before 
362 any parallel context routines start.  The pup routine is never
363 called with a deleting pup handle, so you need not handle that case.
364
365 A C example is:
366 \begin{alltt}
367      int g_arr[17];
368      double g_f;
369      int g_n; /*Length of array below*/
370      float *g_allocated; /*heap-allocated array*/
371  
372      void pup_my_globals(pup_er p)
373      \{
374        pup_ints(p,g_arr,17);
375        pup_double(p,&g_f);
376        pup_int(p,&g_n);
377        if (pup_isUnpacking(p)) \{ /*Arriving on new processor*/
378          g_allocated=malloc(g_n*sizeof(float));
379        \}
380        pup_floats(p,g_allocated,g_n);
381      \}
382 \end{alltt}
383
384 A fortran example is:
385 \begin{alltt}
386      MODULE my_globals_mod
387        INTEGER :: g_arr(17)
388        DOUBLE PRECISION :: g_f
389        INTEGER :: g_n
390        SINGLE PRECISION, ALLOCATABLE :: g_allocated(:)
391      END MODULE
392  
393      SUBROUTINE pup_my_globals(p)
394        IMPLICIT NONE
395        USE my_globals_mod
396        USE pupmod
397        INTEGER :: p
398        call fpup_ints(p,g_arr,17)
399        call fpup_double(p,g_f)
400        call fpup_int(p,g_n)
401        IF (fpup_isUnpacking(p)) THEN
402          ALLOCATE(g_allocated(g_n))
403        END IF
404        call fpup_floats(p,g_allocated,g_n)
405      END SUBROUTINE
406 \end{alltt}
407
408
409 You register your global variable pup routine using the method below.
410 Multiple pup routines can be registered the same way.
411
412 \vspace{0.2in}
413 \function{void TCharmReadonlyGlobals(TCharmPupGlobalFn pup\_fn)}
414 \function{SUBROUTINE tcharm\_readonly\_globals(pup\_fn)}
415     \args{SUBROUTINE :: pup\_fn}
416
417
418
419 \section{Combining Frameworks}
420 \label{sec:combining}
421
422 This section describes how to combine multiple frameworks in a 
423 single application.  You might want to do this, for example,
424 to use AMPI communication inside a finite element method solver.
425
426 You specify how you want the frameworks to be combined by writing
427 a special setup routine that runs when the program starts.
428 The setup routine must be named TCharmUserSetup if written in C, 
429 or tcharm\_user\_setup if written in Fortran.  If you declare a 
430 user setup routine, the standard framework setup routines (such
431 as the FEM framework's \kw{init} routine) are bypassed, and you
432 do all the setup in the user setup routine.
433
434 The setup routine creates a set of threads and then attaches frameworks
435 to the threads.  Several different frameworks can be attached to one thread set,
436 and there can be several sets of threads; however, the most frameworks
437 cannot be attached more than once to single set of threads. That is, a single
438 thread cannot have two attached AMPI frameworks, since the MPI\_COMM\_WORLD 
439 for such a thread would be indeterminate.
440
441 \vspace{0.2in}
442 \function{void TCharmCreateThreads(int nThreads, TCharmThreadStartFn thread\_fn)}
443 \function{SUBROUTINE tcharm\_create\_threads(nThreads,thread\_fn)}
444     \args{INTEGER, INTENT(in) :: nThreads}
445     \args{SUBROUTINE :: thread\_fn}
446
447 Create a new set of \tcharm{} threads of the given size.  The threads will
448 execute the given function, which is normally your user code.  
449 You should call \kw{TCharmGetNumChunks()} (in Fortran, 
450 \kw{tcharm\_get\_num\_chunks()})
451 to get the number of threads from the command line.  This routine can 
452 only be called from your \kw{TCharmUserSetup} routine.
453
454 You then attach frameworks to the new threads.  The order in which
455 frameworks are attached is irrelevant, but attach commands always apply
456 to the current set of threads.
457   
458 The commands to attach the various frameworks are:
459
460 \begin{description}
461 \item[AMPI] You attach a new \kw{MPI\_COMM\_WORLD} to the current threads
462 using the \kw{MPI\_Attach} routine, which takes a string, the name of the
463 communicator.  These threads will then be able to use AMPI calls.
464
465 \item[FEM Framework] You attach the current FEM mesh to the current threads
466 using the \kw{FEM\_Attach} routine, which takes an integer which is normally
467 zero.  These threads will then be able to use FEM calls.  Be sure to set up 
468 an FEM mesh using the \kw{FEM\_Set} calls before your \kw{FEM\_Attach}.
469
470 \item[Multiblock Framework] You attach the current multiblock mesh to the current threads
471 using the \kw{MBLK\_Attach} routine, which takes no parameters.  
472 These threads will then be able to use Multiblock calls.  Be sure to set up 
473 the multiblock mesh using the \kw{MBLK\_Set} calls before your \kw{MBLK\_Attach}.
474
475 \end{description}
476
477 For example, the C code to start an application having one set of threads
478 that performs both AMPI communication and FEM computations inside a 
479 routine called \uw{myDriver} would be:
480
481 \begin{alltt}
482      #include "tcharmc.h"
483      #include "ampi.h"
484      #include "fem.h"
485      
486      /* Called to start the program */
487      void TCharmUserSetup(void)
488      \{
489          TCharmCreateThreads(TCharmGetNumChunks(),myDriver);
490          MPI\_Attach("myAMPIFEM");        
491          ... Usual FEM_Set calls, as normally made from init() ...
492          FEM\_Attach(0);
493      \}
494 \end{alltt}
495
496 The Fortran code to start an application consisting of two sets of threads,
497 both of which perform AMPI communication, would be:
498
499 \begin{alltt}
500      SUBROUTINE tcharm\_user\_setup()
501        IMPLICIT NONE
502        include 'tcharmf.h'
503        include 'ampif.h'
504        
505     ! First set of threads, running "compute1"
506        call tcharm\_create\_threads(tcharm\_get\_num\_chunks(),compute1)
507        call ampi\_attach('part1')
508        
509     ! Second set of threads, running "compute2"
510        call tcharm\_create\_threads(tcharm\_get\_num\_chunks(),compute2)
511        call ampi\_attach('part2')
512      END SUBROUTINE
513 \end{alltt}
514
515
516
517 \section{Command-line Options}
518 \label{sec:cla}
519
520 The complete set of link-time arguments relevant to \tcharm{} is:
521 \begin{description}
522 \item[-memory isomalloc] Enable memory allocation that will automatically
523 migrate with the thread, as described in Section~\ref{sec:isomalloc}.
524
525 \item[-balancer \uw{B}] Enable this load balancing strategy.  The
526 current set of balancers \uw{B} includes RefineLB (make only small changes
527 each time), MetisLB (remap threads using graph partitioning library), 
528 HeapCentLB (remap threads using a greedy algorithm), and RandCentLB
529 (remap threads to random processors).  You can only have one balancer.
530
531 \item[-module \uw{F}] Link in this framework.  The current set of frameworks
532 \uw{F} includes ampi, collide, fem, mblock, and netfem.  You can link in 
533 multiple frameworks.
534
535 \end{description}
536
537 The complete set of command-line arguments relevant to \tcharm{} is:
538
539 \begin{description}
540 \item[+p \uw{N}] Run on \uw{N} physical processors.
541
542 \item[+vp \uw{N}] Create \uw{N} ``virtual processors'', or threads.  This is
543 the value returned by TCharmGetNumChunks.
544
545 \item[++debug] Start each program in a debugger window.  See Charm++
546 Installation and Usage Manual for details.
547
548 \item[+tcharm\_stacksize \uw{N}] Create \uw{N}-byte thread stacks.  This
549 value can be overridden using TCharmSetStackSize().
550
551 \item[+tcharm\_nomig] Disable thread migration.  This can help determine
552 whether a problem you encounter is caused by our migration framework.
553
554 \item[+tcharm\_nothread] Disable threads entirely.  This can help determine
555 whether a problem you encounter is caused by our threading framework.
556 This generally only works properly when using only one thread.
557
558 \item[+tcharm\_trace \uw{F}] Trace all calls made to the framework \uw{F}.
559 This can help to understand a complex program.  This feature is not
560 available if \charmpp{} was compiled with CMK\_OPTIMIZE.
561
562 \end{description}
563
564
565 \input{index}
566 \end{document}