Contents:
Introduction
Compiling
Compiler Requirements
Installing and Configuring POOMA
How to Decipher Compiler Error Messages
Running
POOMA Runtime Arguments
Object-Based Initialization
Debugging
This tutorial includes information on configuring and building the POOMA library, and application programs using POOMA. It also discusses some topics about running POOMA programs, and gives some anecdotal information about debuggers and debugging.
POOMA has been extensively tested with the following C++ compilers:
Other compilers based on version 2.38 or later of the Edison Design Group (EDG) front-end may also be able to compile POOMA. However, we know that CFront-based compilers, Visual C++ 5.0/6.0, and GNU C++ 2.91 do not support the ISO features necessary to compile POOMA. These features include:
In addition, POOMA assumes a fairly standard C++ library including:
Ideally, the library should support ISO standard ".h-less" headers like <vector> that place definitions in the std:: namespace.
The compiler features listed above are an absolute requirement. For example, if your compiler does not support member templates, there is no amount of work that will get POOMA to compile. If your compiler has limited support for these features, it is worth trying to build the library, but there are no assurances of success. Minor deficiencies in the libraries can also be worked around. In fact, we have had to use a mixture of .h-less and .h headers in order to work around various compiler/library problems:
POOMA-based programs can use either .h or non .h headers for everything else in the standard C++ library, but should of course be consistent.
The POOMA build system can handle several different configurations at once; this allows developers to building libpooma.a and POOMA applications for several configurations at the same time. Each configuration is referred to as a suite, and is described by a suite file. This is the main file that the configuration script described below sets up when it runs.
Note: this configuration script is presently available only for Unix platforms. Programmers who are installing POOMA on the Apple Macintosh, or under Microsoft Windows will need to change #define definitions manually. Under CodeWarrior, on both Macintosh and Windows, these definitions are in the file:
pooma-2.2.0/src/arch/Metrowerks/Pooma.prefix.h
If the Intel VTune C++ compiler is being used with Microsoft Visual C++ on Windows, the definitions that need to be changed are in:
pooma-2.2.0/src/arch/Intel/PoomaConfigurations.h
In addition, when the configuration script is run to set up a new suite, it will go through all the subdirectories and create a directory called <suite> in each subdirectory that contains files that will be compiled (where <suite> is the name of the suite). As described below, the environment variable POOMASUITE must be set to the value of the suite to compile after the configuration script is run.
The POOMA configuration script is located in the top level of the POOMA distribution tree, and is called configure. It is written in Perl, and does the following;
#define SOME_POOMA_VARIABLE POOMA_YES #define ANOTHER_POOMA_VARIABLE POOMA_NO
The most useful arguments for configure are:
The mode table in an earlier tutorial summarizes the modes produced by different combinations of configuration flags.
The configure scripts also has options that will add extra -I, -D, -L and other flags to your compilations. Run configure -h to see a complete list of options.
After running configure and creating a suite file, set the environment variable POOMASUITE to the name of the suite, and run make. There is a makefile at the top level of the POOMA distribution, and in the lib/<suite> directory. When make is finished, there should be a lib/<suite>/libpooma.a library file.
This file can be used in one of two ways. Programmers who are extending POOMA can use libpooma.a without any other work, since the library may need to be recompiled often. Such developers can build the programs in the benchmarks and examples directories (such as examples/Doof2d) by running make in those directories.
Programmers who are just using the library will have to install it. Typing make install will install libpooma.a and the necessary source files in the <installdir> directory (specified with the --prefix flag to configure). Users should then set the environment variable POOMADIR to <installdir>, and POOMAARCH to a string indicating the type of build architecture. This is not the same as the <arch> name used for configure, but is instead just a string indicating the type of machine, and for this release may be one of sgi64, sgin32, sgi32, or linux.
After doing all of this, users can go into any subdirectory under examples or benchmarks and run:
make -f Makefile.user
Makefile.user first includes a "stub" makefile from the directory where libpooma.a is installed. This stub makefile contains settings such as POOMA_INCLUDES that are needed to build POOMA applications. For example, the Makefile.user file in examples/Doof2d contains the following:
### include the POOMA makefile stub, to get compiler flags and libraries include $(POOMADIR)/$(POOMAARCH)/lib/Makefile.pooma ### the name of the example code to compile EXAMPLE = Doof2d ### the main target for this makefile $(EXAMPLE): $(EXAMPLE).cpp $(POOMA_CXX) $(POOMA_CXX_DBG_ARGS) -o $(EXAMPLE) $(EXAMPLE).cpp $(POOMA_INCLUDES) $(POOMA_DEFINES) $(POOMA_LIBS)
POOMA makes extensive use of templates to achieve high performance. Unfortunately, this means that a simple mistake often results in dozens of compiler error messages that are both long and obscure. These messages are often tough for experienced C++ programmers to interpret and can be downright scary for newcomers to the language. There is no simple formula for dealing with these messages, but there are strategies that can reduce the pain associated with the process.
To begin with, consider the program below:
01 #include "Pooma/Arrays.h" 02 03 int main(int argc, char *argv[]) 04 { 05 Pooma::initialize(); 06 07 int p, *pp = &p; 08 Array<1> z(6); 09 for (p = 0; p < 6; p++) 10 z(PP) = p; 11 12 Pooma::finalize(); 13 14 return 0; 15 }
KCC 3.3 reports the following impressive set of error messages (please be patient while this scrolls past you):
"src/Array/Array.h", line 416: error: name followed by "::" must be a class or namespace name CTAssert(SDomain_t::dimensions == dimensions); ^ detected during instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp" "src/Array/Array.h", line 416: error: class "PoomaCTAssert<<error-constant>>" has no member "test" CTAssert(SDomain_t::dimensions == dimensions); ^ detected during instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp" "src/Domain/DomainTraits.Loc.h", line 190: error: a value of type "DomainTraitsScalar<int *, int *>::Element_t" cannot be assigned to an entity of type "DomainTraits<Loc<1>>::Storage_t" dom = DomainTraits<T>::getFirst(newdom); ^ detected during: instantiation of "void DomainTraits<Loc<1>>::setDomain(DomainTraits<Loc<1>>::Sto rage_t &, const T &) [with T=int *]" at line 286 of "src/Domain/Domain.h" instantiation of "void SetDomainFunctor<DT, ST, T, UT, wildcard>::setDomain(ST &, const T &) [with DT=DomainTraits<Loc<1>>, ST=DomainBase<DomainTraits<Loc<1>>>::Storage_t, T=DomainTraitsScalar<int *, int *>::PointDomain_t, UT=DomainTraitsScalar<int *, int *>::PointDomain_t, wildcard=false]" at line 395 of "src/Domain/Domain.h" instantiation of "void Domain<1, DT>::setDomain(const T &) [with DT=DomainTraits<Loc<1>>, T=DomainTraitsScalar<int *, int *>::PointDomain_t]" at line 234 of "src/Domain/Loc.h" instantiation of "void CopyLocStorageImpl<Dim, T, 1, false>::copy(Loc<Dim> &, const T &) [with Dim=1, T=int *]" at line 242 of "src/Domain/Loc.h" instantiation of "void CopyLocStorage<Dim, T>::copy(Loc<Dim> &, const T &) [with Dim=1, T=int *]" at line 410 of "src/Domain/Loc.h" instantiation of "Loc<1>::Loc(const T1 &) [with T1=int *]" at line 78 of "src/Array/Array.h" instantiation of "ArrayViewReturn2<Engine, Domain, 1>::Type_t ArrayViewReturn2<Engine, Domain, 1>::eval(const Engine &, const Domain &) [with Engine=Engine<1, double, Brick>, Domain=int *]" at line 89 of "src/Array/Array.h" instantiation of "ArrayViewReturn<Engine, Domain>::Type_t ArrayViewReturn<Engine, Domain>::eval(const Engine &, const Domain &) [with Engine=Engine<1, double, Brick>, Domain=int *]" at line 418 of "src/Array/Array.h" instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp" "src/Domain/NewDomain.h", line 753: error: name followed by "::" must be a class or namespace name SliceType_t retval = AllDomain<SliceType_t::dimensions>(); ^ detected during: instantiation of "NewDomain1<T1>::SliceType_t NewDomain1<T1>::combineSlice(const UT &, const T1 &) [with T1=int *, UT=Interval<1>]" at line 128 of "src/Array/ConstArray.h" instantiation of "TemporaryNewDomain1<Domain, Sub>::SliceType_t TemporaryNewDomain1<Domain, Sub>::combineSlice(const Domain &, const Sub &) [with Domain=Interval<1>, Sub=int *]" at line 419 of "src/Array/Array.h" instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp" "src/Domain/AllDomain.h", line 84: error: class "PoomaCTAssert<<error-constant>>" has no member "test" CTAssert(Dim > 0); ^ detected during: instantiation of "AllDomain<Dim>::AllDomain() [with Dim=<error-constant>]" at line 753 of "src/Domain/NewDomain.h" instantiation of "NewDomain1<T1>::SliceType_t NewDomain1<T1>::combineSlice(const UT &, const T1 &) [with T1=int *, UT=Interval<1>]" at line 128 of "src/Array/ConstArray.h" instantiation of "TemporaryNewDomain1<Domain, Sub>::SliceType_t TemporaryNewDomain1<Domain, Sub>::combineSlice(const Domain &, const Sub &) [with Domain=Interval<1>, Sub=int *]" at line 419 of "src/Array/Array.h" instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp" "src/Domain/NewDomain.h", line 753: error: no suitable conversion function from "AllDomain<<error-constant>>" to "NewDomain1<int *>::SliceType_t" exists SliceType_t retval = AllDomain<SliceType_t::dimensions>(); ^ detected during: instantiation of "NewDomain1<T1>::SliceType_t NewDomain1<T1>::combineSlice(const UT &, const T1 &) [with T1=int *, UT=Interval<1>]" at line 128 of "src/Array/ConstArray.h" instantiation of "TemporaryNewDomain1<Domain, Sub>::SliceType_t TemporaryNewDomain1<Domain, Sub>::combineSlice(const Domain &, const Sub &) [with Domain=Interval<1>, Sub=int *]" at line 419 of "src/Array/Array.h" instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp" "src/Domain/NewDomain.h", line 131: error: expression must have class type DomainTraits<RT>::getDomain(rt, DS + i).setDomain( ^ detected during: instantiation of "void CombineSliceDomainWC<RT, UT, CT, DS, SliceDS, incl, wc>::combine(RT &, const UT &, const CT &) [with RT=NewDomain1<int *>::SliceType_t, UT=Interval<1>, CT=int *, DS=0, SliceDS=0, incl=false, wc=false]" at line 207 instantiation of "void CombineSliceDomain<RT, UT, CT, DS, SliceDS, incl>::combine(RT &, const UT &, const CT &) [with RT=NewDomain1<int *>::SliceType_t, UT=Interval<1>, CT=int *, DS=0, SliceDS=0, incl=false]" at line 766 instantiation of "RT NewDomain1<T1>::fillSlice(RT &, const UT &, const T1 &) [with T1=int *, RT=NewDomain1<int *>::SliceType_t, UT=Interval<1>]" at line 754 instantiation of "NewDomain1<T1>::SliceType_t NewDomain1<T1>::combineSlice(const UT &, const T1 &) [with T1=int *, UT=Interval<1>]" at line 128 of "src/Array/ConstArray.h" instantiation of "TemporaryNewDomain1<Domain, Sub>::SliceType_t TemporaryNewDomain1<Domain, Sub>::combineSlice(const Domain &, const Sub &) [with Domain=Interval<1>, Sub=int *]" at line 419 of "src/Array/Array.h" instantiation of "ArrayViewReturn<ConstArray<Dim, T, Engine>::Engine_t, TemporaryNewDomain1<ConstArray<Dim, T, Engine>::Domain_t, Sub1>::SliceType_t>::Type_t Array<Dim, T, EngineTag>::operator()(const Sub1 &) const [with Dim=1, T=double, EngineTag=Brick, Sub1=int *]" at line 10 of "test.cpp"
The first thing to keep in mind is that the error messages are telling you exactly what went wrong in your program. However, like a patient speaking to a doctor, the compiler is reporting symptoms: "It hurts, here, here, and here." It isn't saying directly, "You have accidentally used an int* to index array z."
Second, start at the first message and work down. As you can see, C++ compilers will often report several different error messages for the same mistake. The first one is usually the most direct statement of what's wrong so start there. In our example, KCC is reporting an error at line 416 of the POOMA header Array/Array.h. This line reads:
CTAssert(SDomain_t::dimensions == dimensions);
It is specifically complaining about the fact that it doesn't think SDomain_t is a class or namespace name, which means that qualifying it with '::' doesn't make sense. This is a symptom, but it isn't very useful, especially to someone who isn't familiar with the innards of POOMA. It may be disconcerting that the error message is in POOMA code. However, it is simply the reality with templates that bad user code can result in a template error deep inside POOMA.
Third, the real information is in the instantiation chain. By "instantiation chain", we mean the set of templates, starting with your code, that the C++ compiler was instantiating when it ran into trouble. In KCC errors, the instantiation chain can be recognized by a series of lines beginning with "detected during: instantiation of". The best way to read these chains is from the instantiation closest to user code to that deepest in POOMA. In the first error message, this is easy because there is only one instantiation listed. KCC claims it trying to instantiate:
Array<Dim, T, Engine>::operator()(const Sub &)
where: Dim is 1, T is double, EngineTag is Brick, and Sub1 is int*, at line 10 of our example program. Now, this is useful because we see that the problem is with the line:
z(PP) = p;
There is indeed a call to operator() call on that line, i.e. z(PP). Moreover, KCC is telling us that the argument we passed in has a type int*, which is not a legal domain type. If we change z(PP) to z(p), the problem is solved.
The other error messages give essentially the same information in different ways. More complicated situations may require following the instantiation chain through several levels. The most important thing is not to get blinded by the quantity of output.
The error messages produced by EGCS are formatted differently, but the procedure for interpreting them is the same. Unfortunately, CodeWarrior Professional 4 does not print out an instantiation chain, which makes diagnosing template problems very difficult. Metrowerks knows about this problem and is fixing it. However, until then, we can only suggest compiling your code with EGCS or KCC as a means to diagnose difficult problems.
The following run-time flags can be used to control various aspects of the behavior of a POOMA-based application:
The set of flags shown below control log messages, warnings, debugging output, and so on. All of these options have a -no form as well, such as --pooma-noinfo.
The first four of the flags above are related to a set of macros defined in the src/Pooma/Pooma.h header file. The first of these, POOMA_PRINT(stream,text), prints a message to a given stream in a thread-safe manner. The second, POOMA_PRINTDEBUG(level,text), prints a message to the POOMA debug output stream POOMA::pdebug if the POOMA_PRINTDEBUG option was selected when POOMA was built. The last three macros are POOMA_INFO(text), POOMA_WARN(text), and POOMA_ERROR(text), which print messages to the information, warning, and error output streams (Pooma::pinfo, Pooma::pwarn, and Pooma::perr respectively). These four streams are actually predefined Inform objects (described in the tutorial on Text I/O).
There are also flags that globally affect certain POOMA classes:
Finally, these three flags are used by POOMA's SMARTS threading package, and are not fully implemented in this release:
As mentioned in the first tutorial, POOMA can be initialized by passing argc and argv to Pooma::initialize(), or by creating an instance of Pooma::Options, configuring it, and then passing that options object to Pooma::initialize(). Thus, instead of using:
a program can do the following:Pooma::initialize(argc, argv);
Pooma::Options opts; // create the options object opts.concurrency(8); // tell POOMA to use 8 threads opts.logfile("pooma.log"); // turn on output logging Pooma::initialize(opts); // initialize Pooma
These two methods can be combined, which allows a program to override any options the user might have specified:
Pooma::Options opts(argc, argv); // parse command line opts.concurrency(8); // but always use 8 threads Pooma::initialize(opts); // actual initialization
For more information on the configuration options available to POOMA programs, please see the POOMA documentation.
Debugging the templated classes and functions in POOMA codes is challenging. Many debuggers have difficulty with finding and stopping in the particular template instance you're interested in. Few, if any, debuggers allow invocation of member functions from objects, whether they are instances of template or nontemplate classes.
Future revisions of this tutorial may include more information on debugging. For now, we include some anecdotal information that may be helpful:
The Metrowerks CodeWarrior Professional 5.2 debugger does a good job of understanding template code, and correctly demangling symbol names. The Windows version is much less successful than the Macintosh version in maintaining proper state when you trace into template functions and template or nontemplate members of template classes. On Windows, it often fails to recognize any local variables.
On IRIX 6.5, we have had some success with dbx, TotalView (TotalView 3.9 or higher, Etnus (http://www.etnus.com)), and SGI's cvd debuggers. The following table indicates combinations of compilers and debuggers on IRIX which are compatible:
TotalView
|
dbx
|
cvd
|
|
KCC |
compatible
|
incompatible
|
incompatible
|
CC |
compatible
|
compatible
|
compatible
|
EGCS (g++) |
incompatible
|
compatible
|
compatible*
|
Compatible compiler/debugger combinations on IRIX 6.5.
*Object member access sometimes crashes cvd with EGCS.
These debuggers fail in some cases to demangle names of objects which are instances of template classes.
See also the discussion of the dbprint() function family. This describes how to set up function prototypes allowing you to examine data values from POOMA containers like Field and Array interactively from some debuggers.
[Prev] | [Home] | [Next] |