advanced
Whole Stage Code Generation
10 min readLast updated: 2026-07-09
Overview
Learn how Whole-Stage Code Generation collapses multiple physical execution steps into a single Java function to eliminate CPU virtual call overhead.
What You Will Learn
In this lesson, you will learn:
- Janino Compiler: Running runtime Java compilation.
- Virtual Method Elimination: Why collapsing plan steps is faster.
- Explain Plan inspection: Locating Whole-Stage Codegen steps in explain logs.
Detailed Concept Explanation
In older Spark versions, processing a row meant passing it through a chain of objects (e.g. Scan -> Filter -> Project), where each step called a virtual method (next()) to retrieve the next row. This created massive CPU virtual call overhead.
Whole-Stage Code Generation solves this by collapsing the physical steps of a query stage into a single Java function at runtime.
Key Benefits
- CPU register locality: Intermediate data is kept in CPU registers instead of being written to JVM memory arrays.
- Janino Compiler: Spark compiles this collapsed Java function directly into bytecode at runtime, running close to hand-written code speeds.
Code Examples
Python (PySpark) Implementation
python
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("Codegen").getOrCreate()
# Simple filter and projection query
df = spark.range(1, 1000)
result = df.filter(df.id > 10).selectExpr("id + 5")
# Codegen stages are marked by star symbols (*) in explain logs
result.explain()
Expected Output
text
== Physical Plan ==
*(1) Project [(id#0L + 5) AS (id + 5)#2L]
+- *(1) Filter (id#0L > 10)
+- *(1) Range (1, 1000, step=1, splits=2)
Execution Plan Diagram (Python & Scala)
Execution Plan Diagram
SparkSession.builder
range(1
1000)
filter(id > 10)
selectExpr(id + 5) [WholeStageCodegen compiled]
explain()
Scala Implementation
scala
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder().appName("CodegenScala").getOrCreate()
val df = spark.range(1, 1000)
val result = df.filter($"id" > 10).selectExpr("id + 5")
result.explain()