-
Notifications
You must be signed in to change notification settings - Fork 28.3k
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
[SPARK-611] Display executor thread dumps in web UI #2944
Changes from all commits
0f198ac
8c10216
87b8b65
cc3e6b3
2b8bdf3
4c87d7f
dfec08b
f4ac1c1
bc1e675
3dfc2d4
b8e69aa
127a130
19707b0
f719266
880f7f7
3c21a5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.spark.executor | ||
|
||
import akka.actor.Actor | ||
import org.apache.spark.Logging | ||
|
||
import org.apache.spark.util.{Utils, ActorLogReceive} | ||
|
||
/** | ||
* Driver -> Executor message to trigger a thread dump. | ||
*/ | ||
private[spark] case object TriggerThreadDump | ||
|
||
/** | ||
* Actor that runs inside of executors to enable driver -> executor RPC. | ||
*/ | ||
private[spark] | ||
class ExecutorActor(executorId: String) extends Actor with ActorLogReceive with Logging { | ||
|
||
override def receiveWithLogging = { | ||
case TriggerThreadDump => | ||
sender ! Utils.getThreadDump() | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,6 +86,9 @@ class BlockManagerMasterActor(val isLocal: Boolean, conf: SparkConf, listenerBus | |
case GetPeers(blockManagerId) => | ||
sender ! getPeers(blockManagerId) | ||
|
||
case GetActorSystemHostPortForExecutor(executorId) => | ||
sender ! getActorSystemHostPortForExecutor(executorId) | ||
|
||
case GetMemoryStatus => | ||
sender ! memoryStatus | ||
|
||
|
@@ -412,6 +415,21 @@ class BlockManagerMasterActor(val isLocal: Boolean, conf: SparkConf, listenerBus | |
Seq.empty | ||
} | ||
} | ||
|
||
/** | ||
* Returns the hostname and port of an executor's actor system, based on the Akka address of its | ||
* BlockManagerSlaveActor. | ||
*/ | ||
private def getActorSystemHostPortForExecutor(executorId: String): Option[(String, Int)] = { | ||
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. This verbosely-named method is the big "hack" for enabling driver -> executor RPC. Basically, I needed to have a way to address the remote |
||
for ( | ||
blockManagerId <- blockManagerIdByExecutor.get(executorId); | ||
info <- blockManagerInfo.get(blockManagerId); | ||
host <- info.slaveActor.path.address.host; | ||
port <- info.slaveActor.path.address.port | ||
) yield { | ||
(host, port) | ||
} | ||
} | ||
} | ||
|
||
@DeveloperApi | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.spark.ui.exec | ||
|
||
import javax.servlet.http.HttpServletRequest | ||
|
||
import scala.util.Try | ||
import scala.xml.{Text, Node} | ||
|
||
import org.apache.spark.ui.{UIUtils, WebUIPage} | ||
|
||
private[ui] class ExecutorThreadDumpPage(parent: ExecutorsTab) extends WebUIPage("threadDump") { | ||
|
||
private val sc = parent.sc | ||
|
||
def render(request: HttpServletRequest): Seq[Node] = { | ||
val executorId = Option(request.getParameter("executorId")).getOrElse { | ||
return Text(s"Missing executorId parameter") | ||
} | ||
val time = System.currentTimeMillis() | ||
val maybeThreadDump = sc.get.getExecutorThreadDump(executorId) | ||
|
||
val content = maybeThreadDump.map { threadDump => | ||
val dumpRows = threadDump.map { thread => | ||
<div class="accordion-group"> | ||
<div class="accordion-heading" onclick="$(this).next().toggleClass('hidden')"> | ||
<a class="accordion-toggle"> | ||
Thread {thread.threadId}: {thread.threadName} ({thread.threadState}) | ||
</a> | ||
</div> | ||
<div class="accordion-body hidden"> | ||
<div class="accordion-inner"> | ||
<pre>{thread.stackTrace}</pre> | ||
</div> | ||
</div> | ||
</div> | ||
} | ||
|
||
<div class="row-fluid"> | ||
<p>Updated at {UIUtils.formatDate(time)}</p> | ||
{ | ||
// scalastyle:off | ||
<p><a class="expandbutton" | ||
onClick="$('.accordion-body').removeClass('hidden'); $('.expandbutton').toggleClass('hidden')"> | ||
Expand All | ||
</a></p> | ||
<p><a class="expandbutton hidden" | ||
onClick="$('.accordion-body').addClass('hidden'); $('.expandbutton').toggleClass('hidden')"> | ||
Collapse All | ||
</a></p> | ||
// scalastyle:on | ||
} | ||
<div class="accordion">{dumpRows}</div> | ||
</div> | ||
}.getOrElse(Text("Error fetching thread dump")) | ||
UIUtils.headerSparkPage(s"Thread dump for executor $executorId", content, parent) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.spark.util | ||
|
||
/** | ||
* Used for shipping per-thread stacktraces from the executors to driver. | ||
*/ | ||
private[spark] case class ThreadStackTrace( | ||
threadId: Long, | ||
threadName: String, | ||
threadState: Thread.State, | ||
stackTrace: String) |
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.
Nice, we had this variable but we just never used it.