Performance

This note is of interest to you if you want to fine-tune Reflex to optimize performance (or rather, limit the performance degradation ;-)). These points go beyond the standard recommendation of using spatial and temporal selection wisely (i.e. hooksets that match only where needed, activation conditions that shut down hooks when needed), and are typically less known. But they can make a great difference.

Synchronization - By default, Reflex uses an initialization strategy for metaobjets which is thread safe. This means that if you use Reflex with lazy initialization mode in a concurrent environment, it will work fine. However, not all applications are concurrent, and synchronization comes at a non-negligeable cost. So you should set the initialization mode of a link accordingly:

  • LAZY_SAFE: lazy initialization thread-safe (has a synchronization cost)
  • LAZY_UNSAFE: lazy initialization without any synchronization (do not use this if you aim at multi-threaded apps)
  • EAGER: eager initialization, thread-safe with no synchronization cost (only limitation: reference to this should not be exposed to another thread during constructor execution).

Type casts - By default, the declared type of a metaobject is Object. This means that in the hook, the metaobject reference is always downcasted to the type that declares the method to invoke. This is nice because you can update metaobject references at runtime quite freely (the mintypes attribute managed by Reflex and complemented by users ensures that a metaobject is type-compatible with the underlying casts in hooks). But in some cases, you do not plan (or want) to update metaobjects dynamically, or you definitely know something precise about the type they should have. In this case, you can use the declared type attribute of a link to specify the declared type of the metaobject reference. Then, in hooks, whenever the declared type actually declares the method to invoke on the metaobject, no cast is included. For information, this optimization detail is used in SOM, and benchmarks proved that this is useful. Type casts are not that cheap in Java.

Context exposure - Reifying information available at a hook and pass it to a metaobject is a major source of performance loss. Using the standard MOP of Reflex is far from optimal, since every piece of available information is reified and packed in a dynamic operation object. When you know the precise minimal protocol your metaobject need, using call descriptors in your link definition is a great source of performance enhancement. Again, our experience in benchmarking SOM highly confirms this. Using call descriptors is also better from a software design point of view (because your metaobjects do not have to implement an overly-generic protocol).

Working set - The previous items were related to runtime performance. To enhance load-time performance (weaving), it is important to specify your working set optimally. Depending on your links and the size of the working set (i.e. the set of classes that are possibly subject to links) the observable weaving time can greatly change.