Skip to content

Instantly share code, notes, and snippets.

@Shreyas-Penkar
Last active September 26, 2025 13:52
Show Gist options
  • Select an option

  • Save Shreyas-Penkar/d6c02b6c589ee1332832dde8626baee3 to your computer and use it in GitHub Desktop.

Select an option

Save Shreyas-Penkar/d6c02b6c589ee1332832dde8626baee3 to your computer and use it in GitHub Desktop.
Pretty UI for Timeline Graph
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Race Condition Timeline</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Roboto Mono', monospace;
background-color: #111827;
color: #F3F4F6;
}
.timeline-container::before {
content: '';
position: absolute;
left: 50%;
top: 0;
bottom: 0;
width: 2px;
background-color: #4B5563;
transform: translateX(-1px);
}
.event {
position: relative;
padding-left: 2rem;
padding-right: 1rem;
margin-bottom: 1rem;
border-left: 2px solid #6B7280;
}
.event::before {
content: '';
position: absolute;
left: -6px;
top: 12px;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: white;
border: 2px solid #111827;
}
.event-a::before { background-color: #3B82F6; }
.event-b::before { background-color: #F59E0B; }
.event-danger::before { background-color: #EF4444; }
</style>
</head>
<body class="p-4 md:p-8">
<div class="max-w-7xl mx-auto">
<h1 class="text-2xl md:text-3xl font-bold text-center mb-4">Race Condition</h1>
<p class="text-center text-gray-400 mb-8">Visualizing a Bug in form of Timeline.</p>
<div class="flex justify-center space-x-6 mb-12">
<div class="flex items-center">
<span class="w-4 h-4 rounded-full bg-blue-500 mr-2"></span>
<span>Thread A </span>
</div>
<div class="flex items-center">
<span class="w-4 h-4 rounded-full bg-amber-500 mr-2"></span>
<span>Thread B </span>
</div>
<div class="flex items-center">
<span class="w-4 h-4 rounded-full bg-red-500 mr-2"></span>
<span>Critical Event / Error</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-8 relative timeline-container">
<!-- Thread A Column -->
<div id="threadA">
<h2 class="text-xl font-semibold text-blue-400 sticky top-4">Thread A</h2>
</div>
<!-- Thread B Column -->
<div id="threadB">
<h2 class="text-xl font-semibold text-amber-400 sticky top-4">Thread B</h2>
</div>
<!-- Race Window -->
<div id="race-window" class="absolute left-0 right-0 border-l-4 border-r-4 border-red-500/50 bg-red-500/10 rounded-lg pointer-events-none">
<div class="absolute -top-3 left-1/2 -translate-x-1/2 bg-red-500 text-white text-xs font-bold px-2 py-0.5 rounded-full">
RACE WINDOW
</div>
</div>
</div>
</div>
<script>
const events = [
{ thread: 'B', time: 0, desc: "Thread B starts" },
{ thread: 'B', time: 100, desc: "Thread B creates first action" },
{ thread: 'B', time: 5100, desc: "Thread B creates second action" },
{ thread: 'B', time: 5150, desc: "❗ Context Invalidation" },
{ thread: 'A', time: 5200, desc: "Thread A enters <code>function_name</code>" },
{ thread: 'A', time: 5250, desc: "Thread A starts <code>function_name</code> – <strong>NO LOCK HELD</strong>" },
{ thread: 'A', time: 5300, desc: "Thread A obtains pointer to <code>variable</code> in the list" },
{ thread: 'A', time: 5350, desc: "⚡ Context switch occurs – Thread A paused" },
{ thread: 'B', time: 5400, desc: "Thread B enters <code>function_name</code>, acquires <code>variable</code>" },
{ thread: 'B', time: 5450, desc: "Thread B identifies action" },
{ thread: 'B', time: 5500, desc: "❗ <code>function_name</code> and <code>function_name</code> executed, freeing the same <code>variable</code> held by Thread A", highlight: 'danger' },
{ thread: 'B', time: 5550, desc: "Thread B releases <code>variable</code> and exits" },
{ thread: 'A', time: 5600, desc: "⚡ Context switch back – Thread A resumes execution" },
{ thread: 'A', time: 5650, desc: "🚨 USE-AFTER-FREE: Thread A accesses <code>variable</code> and <code>variable</code> on freed memory", highlight: 'error' }
];
const timelineSlots = {};
const threadAContainer = document.getElementById('threadA');
const threadBContainer = document.getElementById('threadB');
events.forEach(event => {
const eventEl = document.createElement('div');
const timeKey = Math.floor(event.time / 10) * 10;
if (!timelineSlots[timeKey]) {
timelineSlots[timeKey] = { A: null, B: null };
}
let eventClass = event.thread === 'A' ? 'event-a' : 'event-b';
let borderColor = event.thread === 'A' ? 'border-blue-500' : 'border-amber-500';
if (event.highlight === 'danger' || event.highlight === 'error') {
eventClass = 'event-danger';
borderColor = 'border-red-500';
}
eventEl.className = `event ${eventClass} transform transition-transform duration-300 hover:scale-105`;
eventEl.style.marginLeft = event.thread === 'B' ? '-2px' : '0';
eventEl.innerHTML = `
<div class="flex items-baseline space-x-4">
<div class="font-bold text-gray-400 w-12 text-right">t=${event.time}</div>
<div class="bg-gray-800 rounded-lg p-3 w-full border ${borderColor}/50 shadow-md">
<p class="text-gray-200 text-sm">${event.desc}</p>
</div>
</div>
`;
timelineSlots[timeKey][event.thread] = {el: eventEl, originalEvent: event};
});
const sortedTimes = Object.keys(timelineSlots).map(Number).sort((a,b) => a - b);
sortedTimes.forEach(time => {
const slot = timelineSlots[time];
if (slot.A) threadAContainer.appendChild(slot.A.el);
else {
const placeholder = document.createElement('div');
placeholder.className = 'h-20'; placeholder.style.visibility = 'hidden';
threadAContainer.appendChild(placeholder);
}
if (slot.B) threadBContainer.appendChild(slot.B.el);
else {
const placeholder = document.createElement('div');
placeholder.className = 'h-20'; placeholder.style.visibility = 'hidden';
threadBContainer.appendChild(placeholder);
}
});
function positionRaceWindow() {
const raceWindowEl = document.getElementById('race-window');
// Start = event at t=250, End = event at t=450 // Control the Race Window extent here
const startEl = timelineSlots[5350].A.el;
const endEl = timelineSlots[5550].B.el;
const startTop = startEl.offsetTop + startEl.offsetHeight/2;
const endTop = endEl.offsetTop + endEl.offsetHeight/2;
raceWindowEl.style.top = `${startTop}px`;
raceWindowEl.style.height = `${endTop - startTop}px`;
}
window.addEventListener('load', positionRaceWindow);
window.addEventListener('resize', positionRaceWindow);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment