Polyglot Energy Analysis
Joule can measure and optimize the energy consumption of code written in other languages. The --lift-run flag lifts foreign code into Joule's intermediate representation, applies energy analysis, and executes it with full energy tracking.
Quick Start
# Measure energy in a Python script
joulec --lift-run python script.py
# Measure energy in a JavaScript file
joulec --lift-run js app.js
# Measure energy in C code
joulec --lift-run c program.c
# Apply energy optimization before running
joulec --energy-optimize --lift-run python script.py
# Generate JSON energy report
joulec --lift python script.py --energy-report report.json
# Set energy budget (exit code 1 if exceeded)
joulec --lift python script.py --energy-budget 100nJ
How It Works
The polyglot pipeline has four stages:
-
Parse: The source file is parsed by a language-specific parser (Python, JavaScript, or C) into Joule's
LiftedModulerepresentation. -
Lower: The lifted AST is lowered to MIR (Mid-level IR), the same representation used for native Joule code. Variables, functions, classes, and control flow are all mapped to MIR constructs.
-
Optimize (optional): When
--energy-optimizeis passed, four energy optimization passes are applied to the MIR before execution. -
Execute: The MIR is JIT-compiled via the Cranelift backend and executed in-memory. Energy consumption is tracked throughout execution and reported at the end.
Supported Languages
Python
Comprehensive support for Python syntax and semantics:
| Feature | Status |
|---|---|
| Functions, closures, lambdas | Supported |
| Classes (single and multiple inheritance) | Supported |
| List/dict/set comprehensions | Supported |
| f-strings | Supported |
| Ternary expressions | Supported |
| enumerate/zip | Supported |
| match/case (Python 3.10+) | Supported |
Walrus operator (:=) | Supported |
| try/except/finally | Supported (guard patterns) |
| Slicing with step | Supported |
| Default arguments | Supported |
*args, **kwargs | Supported |
| Generator expressions | Supported |
| String methods (30+) | Supported |
| List methods (20+) | Supported |
| Dict methods (15+) | Supported |
| Math module | Supported |
Print with end= | Supported |
| True division | Supported |
| BigInt overflow handling | Supported |
JavaScript
Comprehensive support for JavaScript syntax and semantics:
| Feature | Status |
|---|---|
| Functions, arrow functions | Supported |
| Classes (single inheritance) | Supported |
| Template literals | Supported |
| Destructuring | Supported |
| Spread operator | Supported |
| switch/case | Supported |
| for-in/for-of | Supported |
| do-while | Supported |
| Bitwise operators | Supported |
| typeof | Supported |
Nullish coalescing (??) | Supported |
Optional chaining (?.) | Supported |
| Array methods (20+) | Supported |
| String methods (15+) | Supported |
| Object methods | Supported |
| Math object | Supported |
| console.log | Supported |
this keyword | Supported |
C
Basic support for C code:
| Feature | Status |
|---|---|
| Functions | Supported |
| Basic types (int, float, double, char) | Supported |
| Arrays | Supported |
| Pointers | Supported |
| Control flow (if, while, for) | Supported |
| stdio (printf, scanf) | Supported |
| math.h functions | Supported |
TypeScript
TypeScript types are erased before analysis — the energy profile is identical to JavaScript. See the TypeScript Guide for details.
| Feature | Status |
|---|---|
| Everything in JavaScript | Supported |
| Type annotations | Stripped |
| Interfaces, type aliases, generics | Stripped |
| Access modifiers (public/private) | Stripped |
| Enums (simple) | Converted to constants |
Go
| Feature | Status |
|---|---|
| Functions, closures, variadic | Supported |
| for, for range, if/else, switch | Supported |
| Slices, maps, structs, methods | Supported |
Goroutines (go) | Supported (sequential analysis) |
Channels (chan, <-) | Supported |
defer | Supported |
| Multiple return values | Supported |
fmt, math, strings, strconv | Supported |
Rust
| Feature | Status |
|---|---|
| Functions, closures, impl blocks | Supported |
| for/while/loop, if/else, match | Supported |
let/let mut, ownership annotations | Supported |
| Structs, enums, Option, Result | Supported |
| Vec, HashMap, String, Box | Supported |
| Iterator chains (.map/.filter/.fold) | Supported |
println!, format!, vec! | Supported |
| Traits (signatures only) | Supported |
Energy Recommendations
When analyzing code, Joule detects common energy anti-patterns and suggests fixes. Categories include:
- ALGORITHM -- Nested loops where a hash set would be O(1)
- ALLOCATION -- Heap allocation inside hot loops
- REDUNDANCY -- Recomputed values that could be hoisted
- DATA STRUCTURE -- Linear search where a set/map is more efficient
- LOOP -- Missing early exits, unbounded iteration
- STRING -- String concatenation in loops (O(n^2))
- MEMORY -- Cache-unfriendly access patterns
- PRECISION -- Float arithmetic where integer suffices
See the per-language guides for language-specific examples of each pattern.
Runtime System
The lift-run runtime provides 100+ shim functions that bridge language-specific operations to native code:
String Operations
str_new, str_concat, str_len, str_print, str_from_int, str_from_float, str_eq, str_index, str_slice, str_contains, str_mul, str_cmp, str_upper, str_lower, str_trim, str_split, str_replace, str_starts_with, str_ends_with, str_index_of, and more.
List Operations
list_new, list_push, list_get, list_set, list_len, list_pop, list_sort, list_reverse, list_copy, list_append, list_index_of, list_contains, list_slice, list_map, list_filter, and more.
Dict Operations
dict_new, dict_set, dict_get, dict_len, dict_get_default, dict_pop, dict_update, dict_setdefault, dict_keys, dict_values, dict_items, dict_contains, and more.
Class Desugaring
Classes from Python and JavaScript are desugared to dictionary-backed standalone functions:
# Python source
class Counter:
def __init__(self, start):
self.count = start
def increment(self):
self.count += 1
return self.count
This is lowered to:
Counter____init__(self, start)-- constructor functionCounter__increment(self)-- method functionselfis a dictionary with fields as key-value pairs
Multiple inheritance is supported using BFS method resolution order (MRO).
Energy Optimization Passes
When --energy-optimize is used, four passes optimize the lifted code:
- Constant Propagation -- Propagate known values, fold constant expressions
- Dead Code Elimination -- Remove unreachable and unused code
- Loop Optimization -- Reduce redundant computation in loops
- Strength Reduction -- Replace expensive operations with cheaper equivalents
Test Coverage
The polyglot pipeline is validated by 1,220 tests across 8 test suites:
| Suite | Count | Description |
|---|---|---|
| Tiered validation | 90 | Core feature coverage |
| Edge cases | 80 | Corner cases and error handling |
| Domain | 100 | 50 Python + 50 JS across 5 domains |
| Stdlib | 100 | 50 Python + 50 JS: string/list methods, default args |
| Classes | 50 | Inheritance, MRO, properties, static methods |
| Advanced | 50 | Closures, generators, decorators, metaclasses |
| Syntax | 50 | Language-specific syntax features |
| Coverage | 700 | Division, print, comprehensions, string ops |
Total: 1,220/1,220 (100% pass rate)
Examples
Python Energy Analysis
# fibonacci.py
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
result = fibonacci(30)
print(f"Result: {result}")
$ joulec --lift-run python fibonacci.py
Result: 832040
Energy consumed: 0.00234 J
JavaScript Energy Analysis
// sort.js
function quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[0];
const left = arr.filter(x => x < pivot);
const right = arr.filter(x => x > pivot);
return [...quickSort(left), pivot, ...quickSort(right)];
}
const data = Array.from({length: 1000}, () => Math.floor(Math.random() * 10000));
const sorted = quickSort(data);
console.log(`Sorted ${sorted.length} elements`);
$ joulec --lift-run js sort.js
Sorted 1000 elements
Energy consumed: 0.00891 J
Energy-Optimized Execution
$ joulec --energy-optimize --lift-run python fibonacci.py
Result: 832040
Energy consumed: 0.00198 J (15.4% reduction)
Static Analysis Mode
For energy analysis without execution, use --lift instead of --lift-run:
# Analyze without running
joulec --lift python script.py
# Output includes per-function energy estimates
This performs the parsing and lowering steps but stops before JIT compilation, producing a static energy report for each function.
Per-Language Guides
For detailed anti-patterns, optimization tips, and worked examples specific to each language:
- Python Guide -- 100+ runtime shims, classes, comprehensions, f-strings
- JavaScript Guide -- Arrow functions, template literals, array methods
- TypeScript Guide -- Type erasure, identical energy to JavaScript
- C Guide -- Memory allocation patterns, cache analysis
- Go Guide -- Goroutines, channels, slice operations
- Rust Guide -- Iterator chains, zero-cost abstractions
Further Reading
- Energy Optimization Walkthrough -- Step-by-step guide from baseline to optimized
- Cross-Language Energy Comparison -- Same algorithm in 6 languages, energy ranked