diff --git a/README.md b/README.md index 2edfcde..cf9e34a 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,13 @@ The Java Thread Dump Analyzer is licensed under the copyright belongs to Spotify AB. ## TODO -* List top RUNNING methods before everything else. I have a thread - dump taken on a system that was swapping basically getting the GC - stuck. With a list of top RUNNING methods it should be possible to - see this from the analysis. +* For top running methods belonging to only one thread, make a link +from the top list method to the thread executing it. + +* Add a Clear button next to the Analyze button. + +* Say "... threads with no stack" for threads with no stack, rather + than "... threads with this stack". * Make the Thread class parse held locks, waited-for locks and waited-for condition variables from the thread dump. @@ -120,3 +123,8 @@ obvious if we need to add something. * Move styling into CSS. * Turn the Ignored Lines section at the bottom into an HTML table. + +* List top RUNNING methods before everything else. I have a thread + dump taken on a system that was swapping basically getting the GC + stuck. With a list of top RUNNING methods it should be possible to + see this from the analysis. diff --git a/analyze.js b/analyze.js index 9e7adac..f3a7018 100644 --- a/analyze.js +++ b/analyze.js @@ -23,15 +23,13 @@ function analyzeTextfield() { // jshint ignore: line var text = document.getElementById("TEXTAREA").value; var analyzer = new Analyzer(text); - setOutputHtml(analyzer.toHtml()); + setHtml("OUTPUT", analyzer.toHtml()); var ignores = analyzer.toIgnoresHtml(); - if (ignores.length > 0) { - setIgnoredHtml(ignores); - } else { - var ignoredDiv = document.getElementById('IGNORED_DIV'); - ignoredDiv.style.display = 'none'; - } + setHtml("IGNORED", ignores); + + var running = analyzer.toRunningHtml(); + setHtml("RUNNING", running); } function htmlEscape(unescaped) { @@ -41,20 +39,12 @@ function htmlEscape(unescaped) { return escaped; } -function setOutputHtml(html) { - var output = document.getElementById("OUTPUT"); - output.innerHTML = html; +function setHtml(name, html) { + var destination = document.getElementById(name); + destination.innerHTML = html; - var outputDiv = document.getElementById('OUTPUT_DIV'); - outputDiv.style.display = 'inline'; -} - -function setIgnoredHtml(html) { - var ignoredTable = document.getElementById("IGNORED"); - ignoredTable.innerHTML = html; - - var ignoredDiv = document.getElementById('IGNORED_DIV'); - ignoredDiv.style.display = 'inline'; + var div = document.getElementById(name + '_DIV'); + div.style.display = (html.length > 0) ? 'inline' : 'none'; } // Extracts a substring from a string. @@ -92,7 +82,7 @@ function Thread(line) { var match = line.match(THREAD_STATE); if (match !== null) { this.threadState = match[1]; - this.running = (this.threadState === "RUNNING") && (this.state === 'running'); + this.running = (this.threadState === "RUNNABLE") && (this.state === 'runnable'); return true; } @@ -196,13 +186,28 @@ function StringCounter() { var string = ""; var countedStrings = this.getStrings(); for (var i = 0; i < countedStrings.length; i++) { + if (string.length > 0) { + string += '\n'; + } string += countedStrings[i].count + - " " + countedStrings[i].string + - '\n'; + " " + countedStrings[i].string; } return string; }; + this.toHtml = function() { + var html = ""; + var countedStrings = this.getStrings(); + for (var i = 0; i < countedStrings.length; i++) { + html += '' + + countedStrings[i].count + + '' + + htmlEscape(countedStrings[i].string) + + "\n"; + } + return html; + }; + this._stringsToCounts = {}; } @@ -353,6 +358,10 @@ function Analyzer(text) { }; this.toHtml = function() { + if (this.threads.length === 0) { + return ""; + } + var threadsAndStacks = this._toThreadsAndStacks(); var asHtml = ""; @@ -385,26 +394,21 @@ function Analyzer(text) { }; this.toIgnoresString = function() { - return this._ignores.toString(); + return this._ignores.toString() + '\n'; }; this.toIgnoresHtml = function() { - var html = ""; - var countedIgnores = this._ignores.getStrings(); - for (var i = 0; i < countedIgnores.length; i++) { - html += '' + - countedIgnores[i].count + - '' + - " " + htmlEscape(countedIgnores[i].string) + - "\n"; - } - return html; + return this._ignores.toHtml(); }; this.toRunningString = function() { return this._getCountedRunningMethods().toString(); }; + this.toRunningHtml = function() { + return this._getCountedRunningMethods().toHtml(); + }; + this._getCountedRunningMethods = function() { var countedRunning = new StringCounter(); for (var i = 0; i < this.threads.length; i++) { @@ -417,11 +421,11 @@ function Analyzer(text) { continue; } - var runningMethod = thread.frames[0].replace(/^\s+at /, ''); + var runningMethod = thread.frames[0].replace(/^\s+at\s+/, ''); countedRunning.addString(runningMethod); } - return countedRunning.getStrings(); + return countedRunning; }; this.threads = []; diff --git a/index.html b/index.html index 119d23c..7b8041a 100644 --- a/index.html +++ b/index.html @@ -36,6 +36,14 @@

Java Thread Dump Analyzer

This page is client-side only, and no data will leave your computer when you click Analyze.

+ +