ganeshashree opened a new pull request, #57708:
URL: https://github.com/apache/spark/pull/57708

   ### What changes were proposed in this pull request?
   
   When a task fails to acquire execution memory, the 
`UNABLE_TO_ACQUIRE_MEMORY` error
   previously reported only the requested and received byte counts:
   
       Unable to acquire 8388608 bytes of memory, got 2097152.
   
   The per-consumer breakdown that `TaskMemoryManager` already computes was 
written only to the executor logs (`showMemoryUsage()`), so it did not travel 
with the task failure reason to the driver or the Spark UI.
   
   This PR attaches that per-consumer attribution to the error message itself:
   
   - New `TaskMemoryManager.getMemoryConsumptionBreakdown()` renders a compact, 
largest-consumer-first breakdown (empty when no consumer holds memory).
   - The rendering is factored around a single `snapshotMemoryUsage()` taken 
under the manager's monitor. On the OOM path, `MemoryConsumer.throwOom()` calls 
the new `logMemoryUsageAndGetBreakdown()`, which snapshots once and produces 
**both** the full executor-log dump and the bounded error breakdown from that 
one snapshot, so the two can never disagree. Snapshotting under the lock 
(rather than sorting live `getUsed()` values) also avoids tripping `TimSort`'s 
"Comparison method violates its general contract!" check on the failure path.
   - The breakdown embedded in the error is bounded by a new internal config 
`spark.memory.oomErrorConsumerBreakdownLimit` (default 5): the largest 
consumers are listed individually, the remainder are collapsed into a single 
summary line that preserves total byte accounting, and `0` omits the breakdown 
from the error entirely. The full, uncapped breakdown is still written to the 
executor logs.
   - A `consumerBreakdown` parameter is added to the `UNABLE_TO_ACQUIRE_MEMORY` 
message template and threaded through both construction sites
     (`SparkCoreErrors.outOfMemoryError` and
     `QueryExecutionErrors.cannotAcquireMemoryForWindowAggregateError`).
   
   ### Why are the changes needed?
   
   OOM debugging is a top operational pain point. When a task dies with
   `UNABLE_TO_ACQUIRE_MEMORY`, the byte counts alone give no signal about which 
operator was holding the memory. The information exists, but only in the 
executor logs, which are often impractical to recover after a failure (rotated 
/ aggregated logs, lost executor) and are not accessible to the driver or to 
automated / agent-based diagnosis. Surfacing which consumers were competing for 
memory at the moment of failure, directly in the error that propagates to the 
driver and the UI, makes these failures far easier to diagnose.
   
   ### Does this PR introduce _any_ user-facing change?
   
   Yes. The `UNABLE_TO_ACQUIRE_MEMORY` error message now includes a bounded 
per-consumer
   memory breakdown. For example:
   
       Unable to acquire 8388608 bytes of memory, got 2097152.
       Memory used by task 4211 grouped by consumer:
         org.apache.spark...UnsafeExternalSorter@1a2b: 456.0 MiB
         org.apache.spark...BytesToBytesMap@3c4d: 12.0 MiB
         (37 more consumers): 44.0 MiB
         (not attributed to a specific consumer): 3.0 MiB
   
   The breakdown exposes only consumer class names, identity hashes, and 
aggregate byte counts
   -- the same data already written to the executor logs; no keys, values, row 
data, or paths.
   This is a change relative to released Spark versions. The new config
   `spark.memory.oomErrorConsumerBreakdownLimit` is internal.
   
   ### How was this patch tested?
   
   New unit tests in `TaskMemoryManagerSuite` cover:
   - largest-first ordering,
   - the cap and the "N more consumers" summary line,
   - the limit-0 (omitted) path,
   - memory not attributed to any consumer,
   - the empty case (no consumer holds memory),
   - end-to-end propagation into the thrown `SparkOutOfMemoryError`, and
   - `logMemoryUsageAndGetBreakdown()` returning the same breakdown as a 
standalone render.
   
   Existing `ShuffleExternalSorterSuite`, `WindowSegmentTreeMemorySuite`, and
   `SparkThrowableSuite` continue to pass (the last confirms the 
error-conditions JSON stays well-formed and round-trips).
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (Claude Opus 4.8)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to