Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
STEM Performance Tips
Performance critical code includes any code used during execution of a STEM simulation. Here are some tips for developers to avoid creating unnecessary objects which increases the workload on the Java garbage collector. The tips were mostly compiled from instrumenting and fixing code for the 1.3.1 release:
1. Avoid creating iterators when looping. For instance, a loop such as
for(Object o:someList)
creates a new iterator object. Instead, just loop using a variable, e.g.
for(int i=0;i<someList.size();++i) Object o = someList.get(i);
2. Avoid autoboxing. For instance, do not invoke:
EObject copy = ECoreUtil.copy(EObject);
The method invokes the eGet method on the EObject which creates new Objects. Instead, commonly copied objects such as IntegrationLabelValues now have a copy method:
IntegrationLabelValue copyVal = val.copy();
This method does not do autoboxing of the double attributes inside.
3. Same tip, do not call
double d = EObject.eGet(EAttribute) or EObject.eSet(EAttribute, double>
on EMF objects. You end up creating unnecessary objects. Again, IntegrationLabelValues (used heavily when running simulations) have a get and set method for doubles that does not do the autoboxing:
IntegrationLabelValue ival = ... ival.set(someEAttribute, double) double v = ival.get(someEAttribute)
EObject.set(EAttribute, ...) will invoke eSet if the EAttribute is not of EType Double (might throw an exception, so be careful). get(EAttribute) will throw an exception right away EAttribute is not of EType Double. We can extend the types supported in the future if needed for new kinds of integration label values (e.g. integers, longs etc.)
4. Keep a pool of objects around instead of creating new ones. This is particularly useful in re-entrant code (true for most methods that calculate deltas in STEM) where each thread grabs an available object and then returns it to the pool when done. There is a new class org.eclipse.stem.core.STEMObjectPool for this purpose. You can create a new pool as such:
STEMObjectPool pool = new STEMObjectPool(10, 5) { @Override protected Object createNewObject() { return new XYZ(); } }
Override the createNewObject() method to specify the types of objects kept in the pool. The two parameters in the constructor (10 and 5 in this example) is the initial size of the pool and increment size when growing the pool. To retrieve an available object from the pool:
Object o = pool.get(); // Reset the object here before you use it to make sure you clear out any state left by the last user of the object.
It's important to remember to return the object to the pool when you're done with it:
pool.release(o);
5. Do not use String concatenation, e.g.
String s = "a"+"b"+"c";
Lots of String objects are created behind the scenes when doing this. Instead, use the StringBuilder() and its append(...) methods.
6. Coming back to step 2 (copy), use object pooling for an even more efficient way to copy IntegrationLabelValues if all you need is a temporary place holder during some calculation:
IntegrationLabelValue ival = (IntegrationLabelValue)pool.get(); ival.set(integrationlabelValueBeingCopied); // Will overwrite any state set by the previous user so it is safe. ... pool.release(ival);