JastAdd supports concurrent attribute evaluation since version 2.3.0. Concurrent attribute code generation is enabled by adding the following flags to the JastAdd command when building a JastAdd project:
--concurrent --rewrite=cnta --safeLazy
The generated code is lock-free for all attribute kinds except parallelized collections.
It should be noted that, as usual, attribute should have no externally visibile side effects. Enabling concurrent evaluation may expose side effects that were previously by deterministic sequential evaluation. For JastAdd projects that are side-effect free it should be possible to seamlessly switch to concurrent attribute evaluation.
We published our work on concurrent attributes at SLE 2017:
J. Öqvist, G. Hedin: Concurrent Circular Reference Attribute Grammars. SLE 2017. http://doi.org/10.1145/3136014.3136032
More information about the concurrent algorithms, with correctness proofs, is available in an extended version of our SLE paper.
The old rewrite mechanism can not be used together with concurrent attributes,
so when concurrent attributes are used JastAdd automatically switches to the
Circular NTA rewrite implementation. If you use rewrites in your project and
want to try the concurrent attributes you should first try to compile with the
--rewrite=cnta --safeLazy flags to ensure that your project works with
Circular NTA rewrites.
Parallelization can be added either by calling attributes from different
threads, or by using parallel collection attributes. Collection attributes can
be automatically parallelized by adding the
@ParallelSurvey annotations to the attribute declaration to parallelize the
collection and/or survey phase of the attribute evaluation.
Parallel collection attributes are implemented by using a thread pool of threads to walk the AST (in the survey phase) and to evaluate contributions (in the collection phase).
In order to make attributes thread safe caching has become more costly, in particular these attributes are extra costly to memoize with the concurrent code generator:
- Parameterized attributes
- Circular attributes
The change in caching cost changes the trade-off between using memoized and non-memoized attributes. To get the best performance it is necessary to reconfigure attribute cache declarations. For small attributes with short evaluation should mostly not be cached, and large attributes with long evaluation times should mostly be cached. However, it depends on how often the attribute is evaluated too: a long-running attribute that is only evaluated once should not be cached.
A branch of the ExtendJ compiler was used to benchmark parallel attribute evaluation. We measured around 2x speedup in error checking with 4-way parallelization on a 4-core machine. Benchmark details and results are described in the technical report.