-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.html
More file actions
110 lines (93 loc) · 4.8 KB
/
index.html
File metadata and controls
110 lines (93 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Concurrency Lock Graph</title>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.js"></script>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
svg { width: 100vw; height: 100vh; }
.lock { fill: orange; } /* 🔒 Locks (Mutexes) */
.thread { fill: steelblue; } /* 🧵 Threads */
.race { stroke: red !important; stroke-width: 3px !important; } /* ⚠️ Race Condition Highlight */
.waiting { stroke-dasharray: 5,5; stroke-width: 2px; stroke: gray; } /* ⏳ Threads Waiting for Lock */
.label { font-size: 14px; fill: black; font-weight: bold; text-anchor: middle; }
</style>
</head>
<body>
<h2>Concurrency Lock Graph (Threads & Mutexes)</h2>
<svg></svg>
<script>
const width = window.innerWidth, height = window.innerHeight;
const svg = d3.select("svg").attr("viewBox", `0 0 ${width} ${height}`).attr("preserveAspectRatio", "xMidYMid meet");
const socket = io("http://localhost:8080", { transports: ["websocket"] });
async function fetchGraph() {
try {
console.log("Fetching graph...");
const response = await fetch("http://127.0.0.1:8080/graph");
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
const data = await response.json();
console.log("Graph data received:", data);
updateGraph(data);
} catch (error) {
console.error("Error fetching graph:", error);
}
}
function updateGraph(data) {
svg.selectAll("*").remove();
const simulation = d3.forceSimulation(data.nodes)
.force("link", d3.forceLink(data.links).id(d => d.id).distance(150)) // Increased spacing
.force("charge", d3.forceManyBody().strength(-500)) // Stronger repulsion to avoid overlap
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(35)); // Avoids node overlap
// 🔗 Edges (Normal, Waiting, Race Condition)
const link = svg.selectAll(".link")
.data(data.links)
.enter().append("line")
.attr("class", d => {
if (d.type === "race_condition") return "race"; // ⚠️ Race Condition
if (d.type === "waiting") return "waiting"; // ⏳ Waiting for Mutex
return "link";
})
.style("stroke", d => d.type === "race_condition" ? "red" : "#999")
.style("stroke-width", 2);
// ⏱️ Edge Labels (Mutex Wait Times)
const edgeLabels = svg.selectAll(".edge-label")
.data(data.links)
.enter().append("text")
.attr("class", "label")
.text(d => d.timestamp ? `⏱️ ${d.timestamp}s` : "");
// 🟠🔵 Nodes (Threads & Locks)
const node = svg.selectAll("circle")
.data(data.nodes)
.enter().append("circle")
.attr("r", d => d.type === "thread" ? 15 : 12) // Bigger for threads
.attr("class", d => d.type === "lock" ? "lock" : "thread")
.call(d3.drag()
.on("start", (event, d) => { if (!event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; })
.on("drag", (event, d) => { d.fx = event.x; d.fy = event.y; })
.on("end", (event, d) => { if (!event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; })
);
// 🏷 Node Labels
const nodeLabels = svg.selectAll(".node-label")
.data(data.nodes)
.enter().append("text")
.attr("class", "label")
.text(d => d.id);
simulation.on("tick", () => {
link.attr("x1", d => d.source.x).attr("y1", d => d.source.y)
.attr("x2", d => d.target.x).attr("y2", d => d.target.y);
node.attr("cx", d => d.x).attr("cy", d => d.y);
nodeLabels.attr("x", d => d.x).attr("y", d => d.y - 20); // Shifted above node
edgeLabels
.attr("x", d => (d.source.x + d.target.x) / 2)
.attr("y", d => (d.source.y + d.target.y) / 2 - 10);
});
}
socket.on("update_graph", data => updateGraph(data));
fetchGraph();
</script>
</body>
</html>