-
Notifications
You must be signed in to change notification settings - Fork 28.7k
[SPARK-12887] Do not expose var's in TaskMetrics #10815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
62c96e1
Add register* methods (get or create)
b9d7fbf
Clean up places where we set OutputMetrics
0785984
Replace set with register
ad094f0
Clean up JsonProtocol
34c7ce5
Hide updatedBlocks
e99b9af
Merge branch 'master' of github.com:apache/spark into get-or-create-m…
202d48e
Merge branch 'master' of github.com:apache/spark into get-or-create-m…
d2e4e23
One more
c04b5df
Review comments
269031f
Remove unused method
12bd943
Add back deprecated things
2f1f6db
Merge remote-tracking branch 'apache/master' into andrewor14-get-or-c…
JoshRosen bfb3c05
Merge pull request #3 from JoshRosen/andrewor14-get-or-create-metrics
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,14 +102,37 @@ class TaskMetrics extends Serializable { | |
private[spark] def incDiskBytesSpilled(value: Long): Unit = _diskBytesSpilled += value | ||
private[spark] def decDiskBytesSpilled(value: Long): Unit = _diskBytesSpilled -= value | ||
|
||
/** | ||
* If this task reads from a HadoopRDD or from persisted data, metrics on how much data was read | ||
* are stored here. | ||
*/ | ||
private var _inputMetrics: Option[InputMetrics] = None | ||
|
||
/** | ||
* Metrics related to reading data from a [[org.apache.spark.rdd.HadoopRDD]] or from persisted | ||
* data, defined only in tasks with input. | ||
*/ | ||
def inputMetrics: Option[InputMetrics] = _inputMetrics | ||
|
||
/** | ||
* Get or create a new [[InputMetrics]] associated with this task. | ||
*/ | ||
private[spark] def registerInputMetrics(readMethod: DataReadMethod.Value): InputMetrics = { | ||
synchronized { | ||
val metrics = _inputMetrics.getOrElse { | ||
val metrics = new InputMetrics(readMethod) | ||
_inputMetrics = Some(metrics) | ||
metrics | ||
} | ||
// If there already exists an InputMetric with the same read method, we can just return | ||
// that one. Otherwise, if the read method is different from the one previously seen by | ||
// this task, we return a new dummy one to avoid clobbering the values of the old metrics. | ||
// In the future we should try to store input metrics from all different read methods at | ||
// the same time (SPARK-5225). | ||
if (metrics.readMethod == readMethod) { | ||
metrics | ||
} else { | ||
new InputMetrics(readMethod) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* This should only be used when recreating TaskMetrics, not when updating input metrics in | ||
* executors | ||
|
@@ -118,18 +141,37 @@ class TaskMetrics extends Serializable { | |
_inputMetrics = inputMetrics | ||
} | ||
|
||
private var _outputMetrics: Option[OutputMetrics] = None | ||
|
||
/** | ||
* If this task writes data externally (e.g. to a distributed filesystem), metrics on how much | ||
* data was written are stored here. | ||
* Metrics related to writing data externally (e.g. to a distributed filesystem), | ||
* defined only in tasks with output. | ||
*/ | ||
var outputMetrics: Option[OutputMetrics] = None | ||
def outputMetrics: Option[OutputMetrics] = _outputMetrics | ||
|
||
@deprecated("setting OutputMetrics is for internal use only", "2.0.0") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know whether there's any third-party code that calls this? Wondering if we can just drop it. Also, AFAIK this would only be for source-compatibility: code which directly set |
||
def outputMetrics_=(om: Option[OutputMetrics]): Unit = { | ||
_outputMetrics = om | ||
} | ||
|
||
/** | ||
* If this task reads from shuffle output, metrics on getting shuffle data will be collected here. | ||
* This includes read metrics aggregated over all the task's shuffle dependencies. | ||
* Get or create a new [[OutputMetrics]] associated with this task. | ||
*/ | ||
private[spark] def registerOutputMetrics( | ||
writeMethod: DataWriteMethod.Value): OutputMetrics = synchronized { | ||
_outputMetrics.getOrElse { | ||
val metrics = new OutputMetrics(writeMethod) | ||
_outputMetrics = Some(metrics) | ||
metrics | ||
} | ||
} | ||
|
||
private var _shuffleReadMetrics: Option[ShuffleReadMetrics] = None | ||
|
||
/** | ||
* Metrics related to shuffle read aggregated across all shuffle dependencies. | ||
* This is defined only if there are shuffle dependencies in this task. | ||
*/ | ||
def shuffleReadMetrics: Option[ShuffleReadMetrics] = _shuffleReadMetrics | ||
|
||
/** | ||
|
@@ -141,66 +183,35 @@ class TaskMetrics extends Serializable { | |
} | ||
|
||
/** | ||
* ShuffleReadMetrics per dependency for collecting independently while task is in progress. | ||
*/ | ||
@transient private lazy val depsShuffleReadMetrics: ArrayBuffer[ShuffleReadMetrics] = | ||
new ArrayBuffer[ShuffleReadMetrics]() | ||
|
||
/** | ||
* If this task writes to shuffle output, metrics on the written shuffle data will be collected | ||
* here | ||
*/ | ||
var shuffleWriteMetrics: Option[ShuffleWriteMetrics] = None | ||
|
||
/** | ||
* Storage statuses of any blocks that have been updated as a result of this task. | ||
*/ | ||
var updatedBlocks: Option[Seq[(BlockId, BlockStatus)]] = None | ||
|
||
/** | ||
* Temporary list of [[ShuffleReadMetrics]], one per shuffle dependency. | ||
* | ||
* A task may have multiple shuffle readers for multiple dependencies. To avoid synchronization | ||
* issues from readers in different threads, in-progress tasks use a ShuffleReadMetrics for each | ||
* dependency, and merge these metrics before reporting them to the driver. This method returns | ||
* a ShuffleReadMetrics for a dependency and registers it for merging later. | ||
*/ | ||
private [spark] def createShuffleReadMetricsForDependency(): ShuffleReadMetrics = synchronized { | ||
val readMetrics = new ShuffleReadMetrics() | ||
depsShuffleReadMetrics += readMetrics | ||
readMetrics | ||
} | ||
* issues from readers in different threads, in-progress tasks use a [[ShuffleReadMetrics]] for | ||
* each dependency and merge these metrics before reporting them to the driver. | ||
*/ | ||
@transient private lazy val tempShuffleReadMetrics = new ArrayBuffer[ShuffleReadMetrics] | ||
|
||
/** | ||
* Returns the input metrics object that the task should use. Currently, if | ||
* there exists an input metric with the same readMethod, we return that one | ||
* so the caller can accumulate bytes read. If the readMethod is different | ||
* than previously seen by this task, we return a new InputMetric but don't | ||
* record it. | ||
* Create a temporary [[ShuffleReadMetrics]] for a particular shuffle dependency. | ||
* | ||
* Once https://issues.apache.org/jira/browse/SPARK-5225 is addressed, | ||
* we can store all the different inputMetrics (one per readMethod). | ||
* All usages are expected to be followed by a call to [[mergeShuffleReadMetrics]], which | ||
* merges the temporary values synchronously. Otherwise, all temporary data collected will | ||
* be lost. | ||
*/ | ||
private[spark] def getInputMetricsForReadMethod(readMethod: DataReadMethod): InputMetrics = { | ||
synchronized { | ||
_inputMetrics match { | ||
case None => | ||
val metrics = new InputMetrics(readMethod) | ||
_inputMetrics = Some(metrics) | ||
metrics | ||
case Some(metrics @ InputMetrics(method)) if method == readMethod => | ||
metrics | ||
case Some(InputMetrics(method)) => | ||
new InputMetrics(readMethod) | ||
} | ||
} | ||
private[spark] def registerTempShuffleReadMetrics(): ShuffleReadMetrics = synchronized { | ||
val readMetrics = new ShuffleReadMetrics | ||
tempShuffleReadMetrics += readMetrics | ||
readMetrics | ||
} | ||
|
||
/** | ||
* Aggregates shuffle read metrics for all registered dependencies into shuffleReadMetrics. | ||
* Merge values across all temporary [[ShuffleReadMetrics]] into `_shuffleReadMetrics`. | ||
* This is expected to be called on executor heartbeat and at the end of a task. | ||
*/ | ||
private[spark] def updateShuffleReadMetrics(): Unit = synchronized { | ||
if (!depsShuffleReadMetrics.isEmpty) { | ||
val merged = new ShuffleReadMetrics() | ||
for (depMetrics <- depsShuffleReadMetrics) { | ||
private[spark] def mergeShuffleReadMetrics(): Unit = synchronized { | ||
if (tempShuffleReadMetrics.nonEmpty) { | ||
val merged = new ShuffleReadMetrics | ||
for (depMetrics <- tempShuffleReadMetrics) { | ||
merged.incFetchWaitTime(depMetrics.fetchWaitTime) | ||
merged.incLocalBlocksFetched(depMetrics.localBlocksFetched) | ||
merged.incRemoteBlocksFetched(depMetrics.remoteBlocksFetched) | ||
|
@@ -212,6 +223,55 @@ class TaskMetrics extends Serializable { | |
} | ||
} | ||
|
||
private var _shuffleWriteMetrics: Option[ShuffleWriteMetrics] = None | ||
|
||
/** | ||
* Metrics related to shuffle write, defined only in shuffle map stages. | ||
*/ | ||
def shuffleWriteMetrics: Option[ShuffleWriteMetrics] = _shuffleWriteMetrics | ||
|
||
@deprecated("setting ShuffleWriteMetrics is for internal use only", "2.0.0") | ||
def shuffleWriteMetrics_=(swm: Option[ShuffleWriteMetrics]): Unit = { | ||
_shuffleWriteMetrics = swm | ||
} | ||
|
||
/** | ||
* Get or create a new [[ShuffleWriteMetrics]] associated with this task. | ||
*/ | ||
private[spark] def registerShuffleWriteMetrics(): ShuffleWriteMetrics = synchronized { | ||
_shuffleWriteMetrics.getOrElse { | ||
val metrics = new ShuffleWriteMetrics | ||
_shuffleWriteMetrics = Some(metrics) | ||
metrics | ||
} | ||
} | ||
|
||
private var _updatedBlockStatuses: Seq[(BlockId, BlockStatus)] = | ||
Seq.empty[(BlockId, BlockStatus)] | ||
|
||
/** | ||
* Storage statuses of any blocks that have been updated as a result of this task. | ||
*/ | ||
def updatedBlockStatuses: Seq[(BlockId, BlockStatus)] = _updatedBlockStatuses | ||
|
||
@deprecated("setting updated blocks is for internal use only", "2.0.0") | ||
def updatedBlocks_=(ub: Option[Seq[(BlockId, BlockStatus)]]): Unit = { | ||
_updatedBlockStatuses = ub.getOrElse(Seq.empty[(BlockId, BlockStatus)]) | ||
} | ||
|
||
private[spark] def incUpdatedBlockStatuses(v: Seq[(BlockId, BlockStatus)]): Unit = { | ||
_updatedBlockStatuses ++= v | ||
} | ||
|
||
private[spark] def setUpdatedBlockStatuses(v: Seq[(BlockId, BlockStatus)]): Unit = { | ||
_updatedBlockStatuses = v | ||
} | ||
|
||
@deprecated("use updatedBlockStatuses instead", "2.0.0") | ||
def updatedBlocks: Option[Seq[(BlockId, BlockStatus)]] = { | ||
if (_updatedBlockStatuses.nonEmpty) Some(_updatedBlockStatuses) else None | ||
} | ||
|
||
private[spark] def updateInputMetrics(): Unit = synchronized { | ||
inputMetrics.foreach(_.updateBytesRead()) | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that's unfortunate. Since it's a pre-existing problem, it's fine to not fix it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before, I guess we'd unconditionally overwrite so we might handle it wrong even for the same read method case? This looks good to me, just curious RE: whether this fixed another bug.