Skip to content

chore: deprecate spark.comet.exec.memoryPool.fraction - #6163

Queued
andygrove wants to merge 5 commits into
apache:mainfrom
andygrove:deprecate-memory-pool-fraction
Queued

andygrove wants to merge 5 commits into
apache:mainfrom
andygrove:deprecate-memory-pool-fraction

Conversation

@andygrove

@andygrove andygrove commented Sep 23, 2026

Copy link
Copy Markdown
Member

Which issue does this PR close?

Part of #4576.

Rationale for this change

The tuning guide recommends setting spark.comet.exec.memoryPool.fraction below 1.0 to leave room in the off-heap pool for native memory that Comet does not reserve. It cannot do that:

  • greedy_unified ignores the fraction. It is built with a pool size of 0 and asks Spark for every byte it reserves.
  • fair_unified applies it to each task's pool, limiting each memory consumer in the task to offHeap.size * fraction / num_consumers. Spark's execution pool already limits each of N running tasks to offHeap.size / N, which is tighter whenever more than one task is running. So on a busy executor the fraction never binds, and the tasks together can still acquire the whole pool.
  • Spark's own off-heap consumers, non-Comet operators and off-heap storage, draw on the same pool with no Comet limit.

The only room Spark leaves for memory outside the pool is spark.executor.memoryOverhead, and the executor memory usage log added in #6162 measures how much of it Comet needs.

What changes are included in this PR?

  • spark.comet.exec.memoryPool.fraction is documented as deprecated, with what it actually does. Its behaviour is unchanged: several tests set it very low to force spills through the fair_unified per-task cap.
  • The driver plugin logs a deprecation warning when the setting is in the SparkConf, pointing at spark.executor.memoryOverhead.
  • The tuning guide and the memory management contributor guide stop recommending it and explain why it does not create headroom.

How are these changes tested?

New CometPluginsMemoryPoolFractionWarningSuite covers the warning being logged when the setting is present and not otherwise. It is registered in both the Linux and macOS PR workflows. The rest is documentation.

…ry usage

Build the alloc-accounting allocator wrapper by default (jemalloc stays
opt-in) and have each executor periodically log its native memory usage
while Comet native plans run:

  Comet native memory usage: allocated 5412.3 MiB, reserved 3890.0 MiB (16 native plans, 8 memory pools)

The first CometExecIterator on an executor starts one daemon thread that
logs a single line per interval for the whole executor, plus one more
after the last plan finishes. It samples on a timer rather than between
batches because a plan rooted at a native shuffle writer, or fed by
native scans, can spend its whole run inside one executePlan call. The
interval is spark.comet.memory.logInterval (default 10s, 0 disables),
read from the executor's SparkConf.

The new Native.getMemoryUsage JNI call reads only the allocation counter
and the pool registry, and reads pool reservations after releasing the
registry lock: CometFairMemoryPool holds its own lock across the JNI
acquire from Spark, which can wait for a finishing task whose
releasePlan needs the registry lock.

Also add a tuning guide section on using the log to size
spark.executor.memoryOverhead, update the tracing and memory management
guides, and switch the rust-test CI step to cover the jemalloc arm and
the build without the feature.
…gistry lock

Remove the alloc-accounting cargo feature: the accounting allocator now
wraps whichever backend the build selects, unconditionally. The
alloc_overhead bench measures the wrapper against the bare backend in
one binary, since there is no longer a build without it.

releasePlan read the remaining pools' reservations while holding the
pool registry lock on every plan, not only when tracing. With
fair_unified that can deadlock: the pool holds its lock across a Spark
acquire that waits on another task, whose releasePlan needs the
registry lock. Every reader now copies the pools out and reads them
after releasing it, and releasePlan reads nothing unless tracing.

A malformed spark.comet.memory.logInterval now disables the log with a
warning instead of failing every Comet task, and a value set only in
the session is reported as ignored.

The log also warns when the executor's native footprint (untracked
native memory plus Spark's off-heap memory in use) exceeds
spark.memory.offHeap.size plus the memory overhead.
The fraction does not reserve room in Spark's off-heap pool: greedy_unified
ignores it, and fair_unified applies it per task, where Spark's own per-task
limit is tighter. Point the warning and the tuning guide at the memory
overhead instead.
The fraction was documented as holding back part of the off-heap pool
for native memory that Comet does not reserve, but it cannot:
greedy_unified ignores it, fair_unified applies it per task where
Spark's own per-task limit is tighter whenever more than one task runs,
and Spark hands out the whole pool either way. The only room Spark
leaves for untracked native memory is spark.executor.memoryOverhead.

Mark the setting deprecated, keep its current behaviour, have the
driver plugin warn when it is set, and correct the tuning and memory
management guides.
@github-actions github-actions Bot added enhancement New feature or request area:memory Memory pools, reservations, OOM handling labels Sep 23, 2026

@sunchao sunchao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Reviewed the full 19-file, four-commit PR diff against main at 97d1c5e4c3d55b3ae6f8c489b37fc717e434b2ed, including the three commits shared with #6162. No reproducible introduced or materially worsened P1/P2 finding was established. Source review is complete. Full integration and workload-performance validation remain incomplete.

  • Prior state and problem: Native allocation accounting was opt-in and required tracing to observe. Pool reservations alone do not describe all native allocations, and registry readers held the registry lock while reading pool reservations. The tuning guidance also presented spark.comet.exec.memoryPool.fraction as an executor-wide headroom control, although its behavior depends on the pool type and cannot guarantee that headroom across all consumers.
  • Design approach: The selected Rust allocator is always wrapped for accounting. A JNI snapshot reports allocations, distinct-pool reservations, pool count, and plan count. One executor daemon logs these figures and evaluates an advisory memory threshold. The final commit documents the fraction as deprecated and adds a driver warning when it is explicitly present in SparkConf.
  • Correctness / compatibility analysis: The snapshot uses process-wide state and clones pool references under the registry lock, then reads reservations after releasing it. The JNI entry point uses the existing exception/panic boundary. The fraction's default, parsing, budget arithmetic, and reservation behavior remain unchanged. The warning reads its configured value without parsing or mutating it. The cumulative change does not alter expression support levels or Spark memory-acquisition rules. The five isolated allocator tests passed in the shared-commit review, and the tested module is byte-identical at this head. Suite registration and git diff --check passed for this PR. Full native/JVM integration and workload benchmarks were not run locally. The Linux native build and Rust tests were running at the last check. Completed visible checks passed, while macOS, Spark SQL, Iceberg, and benchmark jobs were skipped.
  • Key design decisions: Accounting applies to every allocator backend even when logging is disabled. Logging reads executor configuration and uses a timer so long native calls can be sampled. Shared pools are counted once. Reporting does not enforce a new memory budget, and retaining the fraction avoids changing existing spill thresholds.
  • Implementation sketch: AccountingAllocator updates the allocation balance. The pool registry supplies a deduplicated snapshot to Native.getMemoryUsage, and CometExecIterator schedules and formats the log. CometDriverPlugin.init also calls warnIfMemoryPoolFractionSet, which emits the deprecation message when the setting is present. Configuration, tracing, tuning, and contributor documentation describe these changes.
  • Behavioral changes worth calling out: The alloc-accounting Cargo feature is removed because accounting is unconditional. spark.comet.memory.logInterval defaults to 10 seconds and is read from executor configuration. Zero disables periodic logging. The reported balance measures allocations, not RSS, and warnings remain advisory. Applications explicitly setting the fraction receive a deprecation warning, while its existing behavior is retained.
  • Suggested improvements: No additional change met the requested P1/P2 review bar.

# Conflicts:
#	docs/source/contributor-guide/memory_management.md
#	docs/source/user-guide/latest/tuning.md
@andygrove
andygrove marked this pull request as ready for review September 24, 2026 09:28
@andygrove
andygrove enabled auto-merge September 24, 2026 09:29
@andygrove
andygrove added this pull request to the merge queue Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:memory Memory pools, reservations, OOM handling enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants