Skip to content
This repository was archived by the owner on Jan 11, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"freeze": true,
"immed": true,
"indent": 4,
"latedef": "nofunc",
"newcap": true,
"noarg": true,
"noempty": true,
"nonbsp": true,
"nonew": true,
"undef": true,
"unused": true,
"maxdepth": 4,
"maxcomplexity": 6
}
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ the copyright belongs to Spotify AB.
* Make Travis validate the HTML and fail the build if the HTML is
invalid.

* Make Travis run a Javascript code checker and fail the build if there
are warnings.

* Dump all input lines we failed to parse in red at the end so it's
obvious if we need to add something.

Expand Down Expand Up @@ -109,3 +106,6 @@ as the secondary sort key. This way similar stacks will end up closer to
each other.

* Sort thread names in each group alphabetically.

* Make Travis run a Javascript code checker and fail the build if there
are warnings.
89 changes: 47 additions & 42 deletions analyze.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/* global document */

var EMPTY_STACK = " <empty stack>\n";

function analyze_textfield() {
// This method is called from HTML so we need to tell JSHint it's not unused
function analyzeTextfield() { // jshint ignore: line
var text = document.getElementById("TEXTAREA").value;

var analyzer = new Analyzer(text);
Expand All @@ -27,14 +30,14 @@ function analyze_textfield() {
//
// Returns an object with two properties:
// value = the first group of the extracted object
// shorter_string = the string with the full contents of the regex removed
// shorterString = the string with the full contents of the regex removed
function _extract(regex, string) {
var match = regex.exec(string);
if (match === null) {
return {value: undefined, shorter_string: string};
return {value: undefined, shorterString: string};
}

return {value: match[1], shorter_string: string.replace(regex, "")};
return {value: match[1], shorterString: string.replace(regex, "")};
}

function setOutputText(unescaped) {
Expand Down Expand Up @@ -92,39 +95,39 @@ function Thread(line) {
var match;
match = _extract(/\[([0-9a-fx,]+)\]$/, line);
this.dontKnow = match.value;
line = match.shorter_string;
line = match.shorterString;

match = _extract(/ nid=([0-9a-fx,]+)/, line);
this.nid = match.value;
line = match.shorter_string;
line = match.shorterString;

match = _extract(/ tid=([0-9a-fx,]+)/, line);
this.tid = match.value;
line = match.shorter_string;
line = match.shorterString;

match = _extract(/ prio=([0-9]+)/, line);
this.prio = match.value;
line = match.shorter_string;
line = match.shorterString;

match = _extract(/ os_prio=([0-9a-fx,]+)/, line);
this.os_prio = match.value;
line = match.shorter_string;
this.osPrio = match.value;
line = match.shorterString;

match = _extract(/ (daemon)/, line);
this.daemon = (match.value !== undefined);
line = match.shorter_string;
line = match.shorterString;

match = _extract(/ #([0-9]+)/, line);
this.number = match.value;
line = match.shorter_string;
line = match.shorterString;

match = _extract(/ group="(.*)"/, line);
this.group = match.value;
line = match.shorter_string;
line = match.shorterString;

match = _extract(/^"(.*)" /, line);
this.name = match.value;
line = match.shorter_string;
line = match.shorterString;

this.state = line.trim();

Expand All @@ -135,14 +138,35 @@ function Thread(line) {
this._frames = [];
}

function toStackWithHeadersString(stack, threads) {
var string = '';
if (threads.length > 4) {
string += "" + threads.length + " threads with this stack:\n";
}

// Print thread headers for this stack in alphabetic order
var headers = [];
for (var k = 0; k < threads.length; k++) {
headers.push(threads[k].toHeaderString());
}
headers.sort();
for (var l = 0; l < headers.length; l++) {
string += headers[l] + '\n';
}

string += stack;

return string;
}

// Create an analyzer object
function Analyzer(text) {
this._analyze = function(text) {
var lines = text.split('\n');
var currentThread = null;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
while (line.charAt(0) == '"' && line.indexOf('prio=') == -1) {
while (line.charAt(0) === '"' && line.indexOf('prio=') === -1) {
// Multi line thread name
i++;
if (i >= lines.length) {
Expand Down Expand Up @@ -181,22 +205,22 @@ function Analyzer(text) {
stacks.push(stack);
}
stacks.sort(function(a, b) {
if (a == b) {
if (a === b) {
return 0;
}

var a_score = stacksToThreads[a].length;
var scoreA = stacksToThreads[a].length;
if (a === EMPTY_STACK) {
a_score = -123456;
scoreA = -123456;
}

var b_score = stacksToThreads[b].length;
var scoreB = stacksToThreads[b].length;
if (b === EMPTY_STACK) {
b_score = -123456;
scoreB = -123456;
}

if (b_score != a_score) {
return b_score - a_score;
if (scoreB !== scoreA) {
return scoreB - scoreA;
}

// Use stack contents as secondary sort key. This is
Expand All @@ -216,27 +240,8 @@ function Analyzer(text) {
asString += "" + this.threads.length + " threads found:\n";
for (var j = 0; j < stacks.length; j++) {
var currentStack = stacks[j];

asString += '\n';

var threads = stacksToThreads[currentStack];
if (threads.length > 4) {
asString += "" + threads.length + " threads with this stack:\n";
}

// Print thread headers for this stack in alphabetic order
var headers = [];
for (var k = 0; k < threads.length; k++) {
var currentThread = threads[k];

headers.push(threads[k].toHeaderString());
}
headers.sort();
for (var l = 0; l < headers.length; l++) {
asString += headers[l] + '\n';
}

asString += currentStack;
asString += '\n' + toStackWithHeadersString(currentStack, threads);
}

return asString;
Expand Down
12 changes: 11 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/* global require */

var gulp = require('gulp');
var qunit = require('gulp-qunit');
var jshint = require('gulp-jshint');

gulp.task('default', function() {
gulp.task('test', function() {
return gulp.src('./test.html').pipe(qunit());
});

gulp.task('lint', function() {
return gulp.src('*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('fail'));
});
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h1>Java Thread Dump Analyzer</h1>
<p>
<textarea cols='115' rows='10' id='TEXTAREA'></textarea>
<br/>
<input type='submit' value='Analyze' onclick='analyze_textfield();'>
<input type='submit' value='Analyze' onclick='analyzeTextfield();'>
</p>

<div id='OUTPUT_DIV' style="display: none;">
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"bugs": { "url" : "https://github.com/spotify/threaddump-analyzer/issues" },
"scripts": {
"test": "gulp"
"test": "gulp test lint"
},
"keywords": [
"java",
Expand All @@ -18,6 +18,7 @@
],
"devDependencies": {
"gulp-qunit": "~0.2.1",
"gulp-jshint": "1.9.0",
"gulp-util": "~2.2.14",
"gulp": "~3.5.1"
}
Expand Down
10 changes: 8 additions & 2 deletions tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

/* global QUnit */
/* global Thread */
/* global _extract */
/* global Analyzer */
/* global document */

QUnit.test( "thread header 1", function(assert) {
var header = '"thread name" prio=10 tid=0x00007f16a118e000 nid=0x6e5a runnable [0x00007f18b91d0000]';
assert.equal(new Thread(header).toHeaderString(), '"thread name": runnable');
Expand Down Expand Up @@ -131,9 +137,9 @@ QUnit.test( "full dump analysis", function(assert) {
QUnit.test("extract regex from string", function(assert) {
var extracted = _extract(/a(p)a/, "gris");
assert.equal(extracted.value, undefined);
assert.equal(extracted.shorter_string, "gris");
assert.equal(extracted.shorterString, "gris");

extracted = _extract(/a(p)a/, "hejapagris");
assert.equal(extracted.value, "p");
assert.equal(extracted.shorter_string, "hejgris");
assert.equal(extracted.shorterString, "hejgris");
});