Skip to content

Commit

Permalink
Add thread dump SQL console
Browse files Browse the repository at this point in the history
  • Loading branch information
igr committed Mar 27, 2024
1 parent 43fb763 commit 6b40982
Show file tree
Hide file tree
Showing 12 changed files with 363 additions and 11 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ The report contains the following sections:
+ [List of missing locks](doc/report.md#-list-of-missing-locks) - locks that are not released


## TDV SQL Console

Yes, you can query the thread dump using SQL.

+ [SQL Console](doc/console.md)

## TODO

+ [X] Stats per thread pool
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/kotlin/dev/oblac/tdv/app/LocalApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import java.nio.file.Path

fun main() {
generateThreadDumpReport(Path.of("in/Thread.print.20240216120818"))
generateThreadDumpReport(Path.of("in/Thread.print.20240304090236"))
generateThreadDumpReport(Path.of("in/Thread.print.20240304090109"))
generateThreadDumpReport(Path.of("in/Thread.print.20240319144720"))
generateThreadDumpReport(Path.of("in/preprod-Thread-20240320.dump"))
// generateThreadDumpReport(Path.of("in/Thread.print.20240304090236"))
// generateThreadDumpReport(Path.of("in/Thread.print.20240304090109"))
// generateThreadDumpReport(Path.of("in/Thread.print.20240319144720"))
// generateThreadDumpReport(Path.of("in/preprod-Thread-20240320.dump"))

generateThreadDumpReport(Path.of("issues/0001-threaddump.txt.gz"))
generateThreadDumpReport(Path.of("issues/0005-tdump.txt.gz"))
// generateThreadDumpReport(Path.of("issues/0001-threaddump.txt.gz"))
// generateThreadDumpReport(Path.of("issues/0005-tdump.txt.gz"))

}
7 changes: 7 additions & 0 deletions doc/console.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Thread SQL Console

You can query the thread dump using SQL.

![](sql.png)

More tables and relationships will be added.
Binary file added doc/sql.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion domain/src/main/kotlin/dev/oblac/tdv/domain/thread.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlin.time.DurationUnit
@JvmInline
value class ThreadNo(private val value: Int) {
override fun toString() = value.toString()
fun toInt() = value
}

@JvmInline
Expand Down Expand Up @@ -63,7 +64,9 @@ enum class ThreadPriority(val priority: Int) {
P9(9),
P10(10);

companion object {
fun toInt(): Int = priority

companion object {
fun of(i: Int) = ThreadPriority.entries.first { it.priority == i }
fun default() = P5
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ object GenerateReport : (ThreadDump, ThreadDumpAnalysis, String) -> Report {

val compiledTemplateReport = engine.getTemplate("template/report.pebble")
val compiledTemplateThreads = engine.getTemplate("template/threads.pebble")
val compiledTemplateConsole = engine.getTemplate("template/console.pebble")
val reportName = "index.html"
val reportThreadsName = "threads.html"
val reportConsoleName = "console.html"

val context: MutableMap<String, Any> = HashMap()

context["reportName"] =
reportName
context["reportThreadsName"] =
reportThreadsName
context["reportConsoleName"] =
reportConsoleName
context["stats"] =
tda.stats
context["blockTree"] =
Expand Down Expand Up @@ -97,19 +101,22 @@ object GenerateReport : (ThreadDump, ThreadDumpAnalysis, String) -> Report {

val writerReport = StringWriter().also { compiledTemplateReport.evaluate(it, context) }
val writerThreads = StringWriter().also { compiledTemplateThreads.evaluate(it, context) }
val writerConsole = StringWriter().also { compiledTemplateConsole.evaluate(it, context) }

return Report(
listOf(
ReportFile(reportName, writerReport.toString()),
ReportFile(reportThreadsName, writerThreads.toString()),
ReportFile(reportConsoleName, writerConsole.toString()),
ResourceFile("style.css").toReportFile(),
ResourceFile("canvasjs.min.js").toReportFile(),
ResourceFile("d3.v7.min.js").toReportFile(),
ResourceFile("d3-flamegraph.min.css").toReportFile(),
ResourceFile("d3-flamegraph.min.js").toReportFile(),
ResourceFile("charts.js").toReportFile(),
ResourceFile("tree.js").toReportFile(),
ResourceFile("expand-collapse.svg").toReportFile()
ResourceFile("expand-collapse.svg").toReportFile(),
ResourceFile("alasql.js").toReportFile()
)
)
}
Expand Down
7 changes: 7 additions & 0 deletions reporter/src/main/kotlin/dev/oblac/tdv/reporter/stacks.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.oblac.tdv.reporter

import dev.oblac.tdv.domain.AppThreadInfo
import dev.oblac.tdv.domain.Daemon

data class ReportThreadStackFreq(
val state: String,
Expand All @@ -12,13 +13,19 @@ data class ReportThreadStack(
val name: String,
val threadId: String,
val state: String,
val priority: Int,
val daemon: Boolean,
val number: Int,
val stackTrace: List<String>,
) {
companion object {
fun of(threadInfo: AppThreadInfo) = ReportThreadStack(
threadInfo.name.toString(),
threadInfo.tid.toString(),
threadInfo.state.toString(),
threadInfo.priority.toInt(),
threadInfo.daemon == Daemon.DAEMON,
threadInfo.number.toInt(),
threadInfo.stackTrace.flatMap { st ->
listOf(st.toString().trim()) + st.locks.map { it.toString() }
}
Expand Down
158 changes: 158 additions & 0 deletions reporter/src/main/resources/template/alasql.js

Large diffs are not rendered by default.

159 changes: 159 additions & 0 deletions reporter/src/main/resources/template/console.pebble
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{# @pebvariable name="td" type="java.util.List<dev.oblac.tdv.reporter.ReportThreadStack>" #}
{% import "./macros.pebble" %}
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Thread Dump : Console</title>
<link rel="stylesheet" href="style.css">
<script src="alasql.js"></script>
<style>
body {
margin-top:0;
}
h1 {
margin:0;
padding: 0;
}
textarea {
font-family: monospace;
font-size: 16px;
border: 1px solid #333;
padding: 10px;
}

/* CSS */
.button-3 {
appearance: none;
background-color: #2ea44f;
border: 1px solid rgba(27, 31, 35, .15);
border-radius: 6px;
box-shadow: rgba(27, 31, 35, .1) 0 1px 0;
box-sizing: border-box;
color: #fff;
cursor: pointer;
display: inline-block;
font-family: -apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
font-size: 14px;
font-weight: 600;
line-height: 20px;
padding: 6px 16px;
position: relative;
text-align: center;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
vertical-align: middle;
white-space: nowrap;
}

.button-3:focus:not(:focus-visible):not(.focus-visible) {
box-shadow: none;
outline: none;
}

.button-3:hover {
background-color: #2c974b;
}

.button-3:focus {
box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px;
outline: none;
}

.button-3:disabled {
background-color: #94d3a2;
border-color: rgba(27, 31, 35, .1);
color: rgba(255, 255, 255, .8);
cursor: default;
}

.button-3:active {
background-color: #298e46;
box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset;
}
.hint {
font-size: 12px;
font-family: monospace;
color: #666;
margin-top: 10px;
text-align: left;
}
</style>
</head>
<body>
<main id="content">
<h1>Thread Dump SQL Console</h1>
<div>🏡 <a href="{{ reportName }}">report</a></div>

<a id="all"></a>
<textarea id="console" style="width:100%;height:100px">select * from threads</textarea>
<div class="hint">
THREADS: id, name, state, priority, daemon, number
</div>
<div style="margin: 20px;">
<button class="button-3" role="button" onclick="runQuery()">RUN</button>
</div>
<div id="results" class="box" style="width:100%;">
<i>Results will be displayed here</i>
</div>
</main>

<footer>🚀 TDV</footer>
</body>
<script>
const threads = [
{% for t in td %}
{
id: '{{ t.threadId }}',
name: '{{ t.name }}',
state: '{{ t.state }}',
priority: {{ t.priority }},
daemon: {{ t.daemon }},
number: {{ t.number }}
},
{% endfor %}
]
window.onload = function () {
initDatabase();
};
function initDatabase() {
alasql('CREATE TABLE threads (id String, name STRING, state STRING, priority NUMBER, daemon BOOLEAN, number NUMBER)');
alasql.tables.threads.data = threads;
}
function runQuery() {
const query = document.getElementById('console').value;
const results = alasql(query);
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
if (results.length === 0) {
resultsDiv.innerHTML = 'No results';
return;
}
const table = document.createElement('table');
table.classList.add('styled-table');
const thead = document.createElement('thead');
const header = document.createElement('tr');
for (const key in results[0]) {
const th = document.createElement('th');
th.innerText = key;
header.appendChild(th);
}
thead.appendChild(header);
table.appendChild(thead);
const tbody = document.createElement('tbody');
for (const row of results) {
const tr = document.createElement('tr');
for (const key in row) {
const td = document.createElement('td');
td.innerText = row[key];
tr.appendChild(td);
}
tbody.appendChild(tr);
}
table.appendChild(tbody);
resultsDiv.appendChild(table);
}
</script>
</html>
5 changes: 3 additions & 2 deletions reporter/src/main/resources/template/report.pebble
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Thread Dump Report: {{ reportName }}</title>
<title>Thread Dump Report</title>
<link href="d3-flamegraph.min.css" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
Expand All @@ -27,7 +27,8 @@
<a href="#cpu">CPU consuming</a>
<a href="#ust">Identical stack trace</a>
<a href="#missing">Missing locks</a>
<a href="{{ reportThreadsName }}">All&nbsp;Threads</a>
<a href="{{ reportConsoleName }}" class="special">SQL</a>
<a href="{{ reportThreadsName }}" class="special">ALL</a>
</header>
<main id="content">
<h1>ThreadDump Report</h1>
Expand Down
4 changes: 4 additions & 0 deletions reporter/src/main/resources/template/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ header a {
padding: 10px;
letter-spacing: -1px;
}
header a.special {
color: yellow;
font-weight: bold;
}

a {
color: black;
Expand Down
2 changes: 1 addition & 1 deletion reporter/src/main/resources/template/threads.pebble
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Thread Dump : {{ reportThreadsName }}</title>
<title>Thread Dump</title>
<link rel="stylesheet" href="style.css">
<style>
body {
Expand Down

0 comments on commit 6b40982

Please sign in to comment.