Performance problems typically arise from inefficient collection operations, redundant computations, and poorly structured helpers.
Following best practices prevents most performance issues before they occur.
ATL Transformations
Optimise ATL transformations for better performance with large models and complex metamodels.
In this tutorial, you’ll learn performance best practices, identify common bottlenecks, and apply optimisation techniques.
You’ll discover how to write efficient helpers, optimise collection operations, and structure transformations for maximum performance.
Section 1
Performance problems typically arise from inefficient collection operations, redundant computations, and poorly structured helpers.
Following best practices prevents most performance issues before they occur.
Step 1
Identify inefficient patterns.
Common anti-patterns include nested iterations, redundant filtering, and repeated collection traversals.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- ANTI-PATTERN: Nested iterations (O(n²))8helper context Source!Container def: inefficientSearch(): Sequence(Source!Element) =9 self.elements->select(e1 | 10 self.elements->exists(e2 | e2.name = e1.name)11 );
Step 2
Cache expensive computations.
Store expensive computation results in helpers to avoid recalculation.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- OPTIMISED: Cache expensive computation8helper context Source!Container def: elementNames: Set(String) =9 self.elements->collect(e | e.name)->asSet();1011helper context Source!Container def: hasElement(name : String): Boolean =12 self.elementNames->includes(name);
Step 3
Optimise collection operations.
Combine operations and avoid unnecessary intermediate collections.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- OPTIMISED: Chain operations instead of intermediate variables8helper context Source!Container def: activeHighPriorityNames: Sequence(String) =9 self.elements10 ->select(e | e.active)11 ->select(e | e.priority > 5)12 ->collect(e | e.name);
Step 4
Use appropriate rule types.
Choose matched, lazy, or called rules based on transformation requirements.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- Use guards to filter early, avoiding unnecessary processing8rule HighPriorityOnly {9 from10 s: Source!Element (s.priority > 5 and s.active)11 to12 t: Target!Item (13 name <- s.name14 )15}
Section 2
Advanced optimisation focuses on reducing computational overhead, eliminating redundant operations, and measuring actual performance improvements.
These techniques target specific bottlenecks in transformation execution.
Step 1
Minimise helper call overhead.
Reduce the number of helper calls in performance-critical sections.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- Call expensive helper once, reuse result8helper context Source!Container def: statistics: String =9 let count : Integer = self.elements->size() in10 let active : Integer = self.elements->select(e | e.active)->size() in11 'Total: ' + count.toString() + ', Active: ' + active.toString();
Step 2
Avoid unnecessary type checking.
Use guard conditions instead of repeated type checks in bindings.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- Use separate rules with guards instead of type checking in bindings8rule SpecialElementTransform {9 from10 s: Source!SpecialElement -- Type-specific rule11 to12 t: Target!SpecialItem (13 name <- s.name,14 specialProperty <- s.specialValue -- Direct access, no type check needed15 )16}
Step 3
Profile and measure improvements.
Measure transformation performance to identify actual bottlenecks.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- Add timing helpers to measure performance8helper def: timestamp(): String =9 'Processing at time: ' + thisModule.getCurrentTime();1011-- Measure transformation sections to identify bottlenecks
Step 4
Build an optimised transformation.
The complete transformation demonstrates all optimisation techniques working together.
1-- @path Source=/Source/Source.ecore2-- @path Target=/Target/Target.ecore34module OptimisationExample;5create OUT: Target from IN: Source;67-- Optimised helper: cache collection result8helper context Source!Container def: activeElements: Sequence(Source!Element) =9 self.elements->select(e | e.active);1011-- Optimised helper: combine operations12helper context Source!Container def: activeElementNames: Sequence(String) =13 self.activeElements->collect(e | e.name);1415-- Efficient rule using guard to filter early16rule OptimisedTransform {17 from18 s: Source!Container (s.elements->size() > 0)19 to20 t: Target!Item (21 name <- s.name,22 count <- s.activeElements->size(),23 names <- s.activeElementNames24 )25}
Question 1 of 3
What is the most common performance bottleneck in ATL?
Question 2 of 3
When should you cache helper results?
Question 3 of 3
How can you reduce collection operation overhead?
Learn the basics of MTL (Model-to-Text Language) by creating your first code generation template using the OMG MOFM2T standard.