malpp
malpp is a preprocessor abstraction layer for libmalleable: it lets you make an MPI program malleable (able to change its number of processes while it runs) by adding comments above its loops.
Example
With malpp, a malleable sum of squares only needs directives:
long i = 0, iters = 10, sum = 0;
// mal: loop i->iters acc=sum
for (; i < iters; i++) {
sum += i * i;
// mal: check
}
// mal: single
printf("sum=%ld\n", sum);
Without it:
mal_init();
const long total = 10;
long i, limit, sum = 0;
MalFor f = mal_for(total, i, limit);
mal_attach_acc(f, sum);
for (; i < limit; i++) {
sum += i * i;
mal_check_for(f);
}
mal_finalize();
if (mal_rank() == 0)
printf("sum=%ld\n", sum);
Building
malpp is a flex and bison program:
$ make # builds ./malpp $ make test # also needs MPI; clones and builds libmalleable
Usage
It reads a file (or stdin) and writes the expanded source to stdout:
$ malpp program.c > program_malleable.c
Or from a Makefile:
program_malleable.c: program.c
malpp $^ > $@
-O1 or higher: the dispatch
scaffolding malpp emits is correct unoptimized, but only folds away with
optimization.Directives
mal: loop
// mal: loop i->iters declares a single linear loop.
The variables are declared outside, the iterator starts at zero, and
// mal: check must appear in the body.
acc=var adds an accumulator for loops that count or sum.
It must be a type libmalleable can reduce (int,
long, long long, unsigned,
unsigned long, float, double),
and after the loop it is only meaningful on rank 0.
mal: single
// mal: single guards the statement below it so only
rank 0 runs it.
mal: decide
// mal: decide=<func> sets a custom resize
decision function. Guard its definition with #ifdef MALPP
so the sequential build still compiles.
// mal: decide=<path>:<func> loads it at
runtime from a shared library instead, with no guard needed.
See also
- Languages and compilers