1. Charm++ Quickstart
This section gives a concise overview of running your first Charm++ application.
1.1. Installing Charm++
To download the latest Charm++ release, run:
$ wget https://charm.cs.illinois.edu/distrib/charm-latest.tar.gz
$ tar xzf charm-latest.tar.gz
To download the development version of Charm++, run:
$ git clone https://github.com/charmplusplus/charm
To build Charm++, use the following commands:
$ cd charm
$ ./build charm++ netlrts-linux-x86_64 --with-production -j4
This is the recommended version to install Charm++ on Linux systems. For macOS, substitute “linux” with “darwin”, and on ARM64 machines, replace “x86_64” with “arm8”. For advanced compilation options, please see Section 2.6.1 of the manual.
1.2. Parallel “Hello World” with Charm++
The basic unit of computation in Charm++ is a chare, which is a C++ object. Chares have entry methods that can be invoked asynchronously. A Charm++ application consists of collections of chares (such as chare arrays) distributed among the processors of the system.
Each chare has a proxy associated to it, through which other chares can invoke entry methods. This proxy is exposed through the thisProxy member variable, which can be sent to other chares, allowing them to invoke entry methods on this chare.
Each Charm++ application consists of at least two files, a Charm interface (.ci) file, and a normal C++ file. The interface file describes the parallel interface of the application (such as chares, chare arrays, and entry methods), while the C++ files implement its behavior. Please see Section 2.2.1 of the manual for more information about the program structure.
In this section, we present a parallel Hello World example,
consisting of the files hello.ci
and hello.cpp
.
1.2.1. The hello.ci File
The hello.ci
file contains a mainchare, which starts and ends execution,
and a Hello
chare array, whose elements print the “Hello World” message.
Compiling this file creates C++ header files (hello.decl.h
and hello.def.h
)
that can be included in your C++ files.
mainmodule hello {
mainchare Main {
// Main's entry methods
entry Main(CkArgMsg *m);
entry void done();
};
array [1D] Hello {
// Hello's entry methods
entry Hello();
entry void SayHi();
};
};
1.2.2. The hello.cpp File
The hello.cpp
file contains the implementation of the mainchare and chare
array declared in the hello.ci
file above.
#include "hello.decl.h" // created from hello.ci file above
/*readonly*/ CProxy_Main mainProxy;
constexpr int nElem = 8;
/*mainchare*/
class Main : public CBase_Main
{
public:
Main(CkArgMsg* m)
{
//Start computation
CkPrintf("Running Hello on %d processors with %d elements.\n", CkNumPes(), nElem);
CProxy_Hello arr = CProxy_Hello::ckNew(nElem); // Create a new chare array with nElem elements
mainProxy = thisProxy;
arr[0].SayHi(0);
};
void done()
{
// Finish computation
CkPrintf("All done.\n");
CkExit();
};
};
/*array [1D]*/
class Hello : public CBase_Hello
{
public:
Hello() {}
void SayHi()
{
// thisIndex stores the element’s array index
CkPrintf("PE %d says: Hello world from element %d.\n", CkMyPe(), thisIndex);
if (thisIndex < nElem - 1) {
thisProxy[thisIndex + 1].SayHi(); // Pass the hello on
} else {
mainProxy.done(); // We've been around once -- we're done.
}
}
};
#include "hello.def.h" // created from hello.ci file above
1.2.3. Compiling the Example
Charm++ has a compiler wrapper, charmc
, to compile Charm++ applications. Please see
Section 2.6.2 for more information about charmc
.
$ charm/bin/charmc hello.ci # creates hello.def.h and hello.decl.h
$ charm/bin/charmc hello.cpp -o hello
1.2.4. Running the Example
Charm++ applications are started via charmrun
,
which is automatically created by the charmc
command above.
Please see Section 2.6.3 for more information about charmrun
.
To run the application on two processors, use the following command:
$ ./charmrun +p2 ./hello
Charmrun> scalable start enabled.
Charmrun> started all node programs in 1.996 seconds.
Charm++> Running in non-SMP mode: 1 processes (PEs)
Converse/Charm++ Commit ID: v6.9.0-172-gd31997cce
Charm++> scheduler running in netpoll mode.
CharmLB> Load balancer assumes all CPUs are same.
Charm++> Running on 1 hosts (1 sockets x 4 cores x 2 PUs = 8-way SMP)
Charm++> cpu topology info is gathered in 0.000 seconds.
Running Hello on 2 processors with 8 elements.
PE 0 says: Hello world from element 0.
PE 0 says: Hello world from element 1.
PE 0 says: Hello world from element 2.
PE 0 says: Hello world from element 3.
PE 1 says: Hello world from element 4.
PE 1 says: Hello world from element 5.
PE 1 says: Hello world from element 6.
PE 1 says: Hello world from element 7.
All done
[Partition 0][Node 0] End of program
1.3. Where to go From Here
The
tests/charm++/simplearrayhello
folder in the Charm++ distribution has a more comprehensive example, from which the example in this file was derived.The main Charm++ manual (https://charm.readthedocs.io/) contains more information about developing and running Charm++ applications.
Charm++ has lots of other features, such as chare migration, load balancing, and checkpoint/restart. The main manual has more information about them.
AMPI (https://charm.readthedocs.io/en/latest/ampi/manual.html) is an implementation of MPI on top of Charm++, allowing MPI applications to run on the Charm++ runtime mostly unmodified.
Charm4py (https://charm4py.readthedocs.io) is a Python package that enables development of Charm++ applications in Python.