Basic "Hello World" Program

The figure below presents the code for the most basic "Hello World" program that can be written using Charm++. The program only has a single chare object (the main chare object that is auto-generated by the Charm++ Runtime System). The main chare object simply prints a "Hello World" message to standard output and then exits. The source code for this example can be downloaded here (BasicHelloWorld.tar.gz). (Remember to set the CHARMDIR in the Makefile!)

Header File (main.h) Source File (main.C)
#ifndef __MAIN_H__
#define __MAIN_H__

class Main : public CBase_Main { (1)

 public:
  Main(CkArgMsg* msg); (2)
  Main(CkMigrateMessage* msg); (3)

};

#endif //__MAIN_H__
#include "main.decl.h" (6)
#include "main.h"

// Entry point of Charm++ application
Main::Main(CkArgMsg* msg) {

  // Print a message for the user
  CkPrintf("Hello World!\n"); (4)

  // Exit the application (5)
  CkExit();
}

// Constructor needed for chare object migration (ignore
// for now) NOTE: This constructor does not need to
// appear in the ".ci" file
Main::Main(CkMigrateMessage* msg) { }

#include "main.def.h" (6)
Interface File (main.ci) Makefile
mainmodule main { (7)

  mainchare Main { (8)
    entry Main(CkArgMsg* msg); (9)
  };

};
CHARMDIR = [put Charm++ install directory here] (10)
CHARMC = $(CHARMDIR)/bin/charmc $(OPTS) (11)

default: all
all: hello

hello : main.o
   $(CHARMC) -language charm++ -o hello main.o (12)

main.o : main.C main.h main.decl.h main.def.h
   $(CHARMC) -o main.o main.C (13)

main.decl.h main.def.h : main.ci
   $(CHARMC) main.ci (14)

clean:
   rm -f main.decl.h main.def.h main.o hello charmrun
Figure 1: Source code and Makefile for Basic "Hello World" Program

The Header File (main.h)

The header file for a chare class in Charm++ is basically the same as it would be for a class in C++. There are a few items that are worth mentioning though:

(1) Chare classes inherit from parent classes which are auto-generated by the Charm++ tools during compilation. Also, there is nothing that forces the name of the mainchare to be "Main". This is simply convention. The main chare is specified in the ".ci" file using the mainchare keyword.
(2) This is the entry point of the application. This constructor is automatically called by the Charm++ Runtime System when the application starts. The CkArgMsg message passed to it contains command line arguments that were specified by the user.
(3) This is a constructor that is used for chare object migration (the Charm++ Runtime System can dynamically migrate chare objects between processing elements). For now, just include this constructor but do not worry about what it does.

The Source File (main.C)

The source file for a chare class in Charm++ is basically the same as it would be for a class in C++.

(4) CkPrintf() is a special version of the printf() function provided by C/C++. For the purpose of this example, the difference doesn't matter. However, CkPrintf() is designed to re-route the output of all processing elements to a single point which can be viewed by the user. Otherwise, it is the same as printf().
(5) CkExit() is a special version of the exit() function provided by C/C++. For Charm++ applications, this function must be called to cause the program to exit (unlike C/C++ where returning from main() will also cause the program to exit). CkExit() does not return on the processing element that it was called on and causes all other processing elements being used by the application to also exit the application.
(6) The "main.decl.h" and "main.def.h" files are auto-generated by the Charm++ tools during the compilation process. They contain code that is used to hook the application code to the Charm++ Runtime System, they declare parent classes for chare classes, and so on. The "decl.h" file should be included at the beginning of the source file and the "def.h" file should be included at the very end of the source file.

The Interface File (main.ci)

(7) This declares the interface module. For the purpose of this example, the important thing to know is that the "main" keyword is used to name the generated files (the "main.decl.h" and "main.def.h" files).
(8) This line declares the main chare for the application. In this example, the "Main" class is declared as the main chare class. The Charm++ Runtime System will create an instance of the Main chare class (execution of the program begins with the execution of this Main chare object's constructor).
(9) This line declares one of the member functions (in this case, a constructor) of the Main chare class as an entry method. This means that other chare objects and the Charm++ Runtime System can send a chare object of this type messages destined for this entry method (i.e. other chare objects in the global object space can invoke this entry method on a Main chare object).

Makefile

(10) The path to the root directory of an installation of the Charm++ distribution should be placed here.
(11) Charmc is a tool specific to Charm++. It serves as a wrapper for the native linker and compiler on a given system (along with providing some additional functionality). This allows a programmer to write a Makefile that uses charmc as the compiler and then re-use the same Makefile on various platforms (making the Makefile itself portable regardless of the compilers used on the various systems).
(12) In this case, charmc is being used as a linker. There is only one programmer specified object file, however, the standard C/C++ libraries and the libraries containing the Charm++ Runtime System are also being linked into the final application at this point. Additionally, another program called charmrun will be created in the same directory which will allow the user to launch their application on multiple processing elements at a time (or the user can just run their application directly, in this case using "./hello", which will cause it to only run on the local machine).
(13) In this case, charmc is being used as a compiler. Charmc will basically just call the native compiler on the system to create the object file from the source file.
(14) In this case, charmc is being used to auto-generate the "main.decl.h" and "main.def.h" files. These files contain the hooks needed to allow the application code and the Charm++ Runtime System to interoperate.

Output of the Basic "Hello World" Program

Below is the output of the basic "Hello World" example program. The first line is the command used to launch the program. Since this program only has a single chare object, executing it on more than a single processor using charmrun does not make any sense (the other processors will have no chare objects on them). The next example program will have multiple objects and demonstrate using charmrun to launch a Charm++ program. The second line simply indicates to the user that the program is being executed on a single processor (i.e. charmrun was not used). The third line is the output from the CkPrintf() statement in Main::Main(CkArgMsg*). The fourth and final line is printed by the Charm++ Runtime System to indicate that the program has exited (only when the program is run in standalone mode).

$ ./hello
Charm++: standalone mode (not using charmrun)
Hello World!
Program finished.
Figure: Output of the Basic "Hello World" Program