Skip to content

Instantly share code, notes, and snippets.

@ntfshard
Created June 11, 2024 11:07
Show Gist options
  • Save ntfshard/f5bb893eaf31cceea27a377abf2aca1f to your computer and use it in GitHub Desktop.
Save ntfshard/f5bb893eaf31cceea27a377abf2aca1f to your computer and use it in GitHub Desktop.
valgrind xml report viewer (very sketchy)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/4.4.0/fxparser.min.js"></script>
<script lang="js">
let data = {};
let kind = {};
function init() {
document.getElementById('fileInput').addEventListener('change', handleFileSelect, false);
document.getElementById('showButton').addEventListener('click', show, false);
}
function handleFileSelect(event) {
const reader = new FileReader();
reader.onload = handleFileLoad;
reader.onerror = alert;
reader.onprogress = function(env) {console.log(env);};
reader.readAsText(event.target.files[0]);
}
function getStackArr(record) {
if (Array.isArray(record.stack)) {
return record.stack[0].frame;
} else {
return record.stack.frame;
}
}
function handleFileLoad(event) {
console.log(event);
//console.log(event.target.result);
try {
const parser = new XMLParser();
data = parser.parse(event.target.result);
console.log(data);
kind = {};
kind_size = {};
for (let i = 0; i < data.valgrindoutput.error.length; ++i) {
let rec = data.valgrindoutput.error[i];
kind[rec.kind] = (kind[rec.kind] || 0) + 1;
if (rec.hasOwnProperty("xwhat")) {
kind_size[rec.kind] = (kind_size[rec.kind] || 0) + rec.xwhat.leakedbytes;
}
}
} catch(error) {
alert(error)
return;
}
{
let parent = document.getElementById("kind");
parent.replaceChildren();
const keys = Object.keys(kind);
for (let i = 0; i < keys.length; ++i) {
let elem = document.createElement("option");
let key = keys[i];
elem.value = key;
elem.innerText = key + ": " + kind[key].toString();
if (kind_size.hasOwnProperty(key)) {
elem.innerText += " " + kind_size[key].toString() + ' bytes';
}
parent.appendChild(elem);
}
}
document.getElementById("showButton").disabled = false;
}
function show() {
let parent = document.getElementById("content");
parent.replaceChildren();
const filterKinds = Array.from(document.getElementById("kind").selectedOptions).map(({ value }) => value);
console.log(filterKinds);
const hideBlind = document.getElementById("hideBlind").checked;
let fncounter = {};
let counter = 0;
for (let i = 0; i < data.valgrindoutput.error.length; ++i) {
// reverse order
const index = data.valgrindoutput.error.length - i -1;
if (!filterKinds.includes(data.valgrindoutput.error[index].kind)) {
continue;
}
const stack = getStackArr(data.valgrindoutput.error[index]);
if (hideBlind) {
// stack.frame[0] -- valgrind function
if (stack.length >= 3 && (!stack[0].hasOwnProperty('fn') || !stack[1].hasOwnProperty('fn') || !stack[2].hasOwnProperty('fn'))) {
continue;
}
}
let cont = false;
// todo switchable: has/not symbol | has/not obj
for (let j = 0; j < stack.length/2; ++j) { // most of time it's in a first half
if (stack[j].fn == "__static_initialization_and_destruction_0") {
cont = true;
break;
}
}
if (cont) continue;
/*cont = true;
for (let j = 0; j < stack.length/2; ++j) { // most of time it's in a first half
if (stack[j].obj == "/usr/local/lib/gz-rendering-7/engine-plugins/libgz-rendering7-ogre2.so.7.4.0") {
cont = false;
break;
}
}
if (cont) continue;*/
/*for (let j = 0; i < stack.length; ++i) { // most of time it's in a first half
if (stack[j].hasOwnProperty("fn")) {
fncounter[stack[j].fn] = (fncounter[stack[j].fn] || 0) + 1;
}
}*/
renderData(parent, data.valgrindoutput.error[index]);
// show only 2k lines
/*++counter;
if (counter > 2048) {break;}
*/
}
console.log("done: ", counter);
//console.log(fncounter);
}
function renderData(parent, record) {
let elem = document.createElement("p");
let what = document.createElement("div");
let stk = document.createElement("ul");
if (record.hasOwnProperty('xwhat')) {
what.innerText = JSON.stringify(record.xwhat);
} else if(record.hasOwnProperty('what')) {
what.innerText = JSON.stringify(record.what);
} else {
what.innerText = "No what/xwhat";
}
let stack = getStackArr(record);
for (let i = 0; i < stack.length; ++i) {
let frame = document.createElement("li");
frame.innerText = JSON.stringify(stack[i]);
stk.appendChild(frame);
}
elem.appendChild(what);
elem.appendChild(stk);
parent.appendChild(elem);
}
</script>
</head>
<body onload="init()" style="background-color: gray">
<div id="toolbox">
<select name="kind" id="kind" multiple></select>
<input id="showButton" type="button" value="show" disabled="true" />
<input id="hideBlind" type="checkbox" checked="true" />
<input id="fileInput" type="file" name="file" />
</div>
<div id="content">cmd prefix: valgrind --leak-check=full --trace-children=yes --max-stackframe=8377808 --num-callers=64 --track-origins=yes --xml=yes --xml-file=report%p.xml</div>
</body>
</html>
@ntfshard
Copy link
Author

I'm not web developer, but I know that sync button handler is bad. But it able to solve a problem with filteing and sorting. If you want to contribute/improve/give advice, I coud start a normal repo.

If you want to re-use it, this code is under MIT license

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment