Created
October 17, 2025 19:30
-
-
Save bcardarella/faa85965250279c3041a33e8ef905d80 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>DOM Benchmark Results</title> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| } | |
| header { | |
| background: white; | |
| padding: 30px; | |
| border-radius: 10px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.2); | |
| margin-bottom: 30px; | |
| } | |
| h1 { | |
| color: #333; | |
| font-size: 2.5em; | |
| margin-bottom: 10px; | |
| } | |
| .subtitle { | |
| color: #666; | |
| font-size: 1.1em; | |
| } | |
| .implementations { | |
| display: flex; | |
| gap: 15px; | |
| margin-top: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .impl-badge { | |
| padding: 8px 16px; | |
| border-radius: 20px; | |
| font-size: 0.9em; | |
| font-weight: 600; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .impl-zig { background: #f9a825; color: white; } | |
| .impl-chromium { background: #4285f4; color: white; } | |
| .impl-firefox { background: #ff6611; color: white; } | |
| .impl-webkit { background: #00aaff; color: white; } | |
| .category { | |
| background: white; | |
| padding: 30px; | |
| border-radius: 10px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.2); | |
| margin-bottom: 30px; | |
| } | |
| .category h2 { | |
| color: #333; | |
| margin-bottom: 20px; | |
| font-size: 1.8em; | |
| } | |
| .chart-container { | |
| position: relative; | |
| height: 400px; | |
| margin-bottom: 30px; | |
| } | |
| .stats-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin-top: 20px; | |
| } | |
| .stats-table th, | |
| .stats-table td { | |
| padding: 12px; | |
| text-align: left; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .stats-table th { | |
| background: #f5f5f5; | |
| font-weight: 600; | |
| color: #333; | |
| } | |
| .stats-table tr:hover { | |
| background: #f9f9f9; | |
| } | |
| .winner { | |
| font-weight: 600; | |
| color: #4caf50; | |
| } | |
| .speedup { | |
| font-size: 0.9em; | |
| color: #666; | |
| } | |
| footer { | |
| text-align: center; | |
| color: white; | |
| padding: 20px; | |
| opacity: 0.8; | |
| } | |
| .legend { | |
| display: flex; | |
| gap: 20px; | |
| margin-top: 15px; | |
| flex-wrap: wrap; | |
| } | |
| .legend-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .legend-color { | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 4px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <h1>🚀 DOM Benchmark Results</h1> | |
| <p class="subtitle">Performance comparison: Zig vs Browser Implementations</p> | |
| <div class="implementations"> | |
| <div class="impl-badge impl-zig"> | |
| <span>●</span> Zig | |
| </div> | |
| <div class="impl-badge impl-chromium"> | |
| <span>●</span> Chromium | |
| </div> | |
| <div class="impl-badge impl-firefox"> | |
| <span>●</span> Firefox | |
| </div> | |
| <div class="impl-badge impl-webkit"> | |
| <span>●</span> WebKit | |
| </div> | |
| </div> | |
| </header> | |
| <div class="category"> | |
| <h2>ID Queries</h2> | |
| <div class="chart-container"> | |
| <canvas id="chart-0"></canvas> | |
| </div> | |
| <table class="stats-table"> | |
| <thead> | |
| <tr> | |
| <th>Benchmark</th> | |
| <th>Zig</th><th>Chromium</th><th>Firefox</th><th>WebKit</th> | |
| <th>Winner</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>getElementById: Small DOM (100)</strong></td> | |
| <td>29µs<span class="speedup"> (2.1x slower)</span></td><td>14µs<span class="speedup"></span></td><td>26µs<span class="speedup"> (1.9x slower)</span></td><td>25µs<span class="speedup"> (1.8x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>getElementById: Medium DOM (1000)</strong></td> | |
| <td>216µs<span class="speedup"> (1.5x slower)</span></td><td>143µs<span class="speedup"></span></td><td>274µs<span class="speedup"> (1.9x slower)</span></td><td>253µs<span class="speedup"> (1.8x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>getElementById: Large DOM (10000)</strong></td> | |
| <td>11ms<span class="speedup"> (7.4x slower)</span></td><td>1ms<span class="speedup"></span></td><td>3ms<span class="speedup"> (1.9x slower)</span></td><td>3ms<span class="speedup"> (1.7x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementById (100 elem)</strong></td> | |
| <td>5ns<span class="speedup"></span></td><td>93ns<span class="speedup"> (18.7x slower)</span></td><td>102ns<span class="speedup"> (20.4x slower)</span></td><td>77ns<span class="speedup"> (15.4x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementById (1000 elem)</strong></td> | |
| <td>5ns<span class="speedup"></span></td><td>93ns<span class="speedup"> (18.6x slower)</span></td><td>100ns<span class="speedup"> (20.0x slower)</span></td><td>72ns<span class="speedup"> (14.4x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementById (10000 elem)</strong></td> | |
| <td>4ns<span class="speedup"></span></td><td>97ns<span class="speedup"> (24.2x slower)</span></td><td>103ns<span class="speedup"> (25.7x slower)</span></td><td>71ns<span class="speedup"> (17.7x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector #id (100 elem)</strong></td> | |
| <td>13ns<span class="speedup"></span></td><td>102ns<span class="speedup"> (7.8x slower)</span></td><td>170ns<span class="speedup"> (13.1x slower)</span></td><td>160ns<span class="speedup"> (12.3x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector #id (1000 elem)</strong></td> | |
| <td>14ns<span class="speedup"></span></td><td>94ns<span class="speedup"> (6.7x slower)</span></td><td>170ns<span class="speedup"> (12.1x slower)</span></td><td>150ns<span class="speedup"> (10.7x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector #id (10000 elem)</strong></td> | |
| <td>15ns<span class="speedup"></span></td><td>97ns<span class="speedup"> (6.5x slower)</span></td><td>170ns<span class="speedup"> (11.3x slower)</span></td><td>170ns<span class="speedup"> (11.3x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="category"> | |
| <h2>Tag Queries</h2> | |
| <div class="chart-container"> | |
| <canvas id="chart-1"></canvas> | |
| </div> | |
| <table class="stats-table"> | |
| <thead> | |
| <tr> | |
| <th>Benchmark</th> | |
| <th>Zig</th><th>Chromium</th><th>Firefox</th><th>WebKit</th> | |
| <th>Winner</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>Pure query: getElementsByTagName (100 elem)</strong></td> | |
| <td>5µs<span class="speedup"> (67.6x slower)</span></td><td>89ns<span class="speedup"> (1.2x slower)</span></td><td>121ns<span class="speedup"> (1.6x slower)</span></td><td>74ns<span class="speedup"></span></td> | |
| <td class="winner">WebKit</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementsByTagName (1000 elem)</strong></td> | |
| <td>5µs<span class="speedup"> (68.5x slower)</span></td><td>86ns<span class="speedup"> (1.2x slower)</span></td><td>123ns<span class="speedup"> (1.7x slower)</span></td><td>73ns<span class="speedup"></span></td> | |
| <td class="winner">WebKit</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementsByTagName (10000 elem)</strong></td> | |
| <td>7µs<span class="speedup"> (83.4x slower)</span></td><td>84ns<span class="speedup"></span></td><td>137ns<span class="speedup"> (1.6x slower)</span></td><td>130ns<span class="speedup"> (1.5x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector tag (100 elem)</strong></td> | |
| <td>15ns<span class="speedup"></span></td><td>206ns<span class="speedup"> (13.7x slower)</span></td><td>290ns<span class="speedup"> (19.3x slower)</span></td><td>240ns<span class="speedup"> (16.0x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector tag (1000 elem)</strong></td> | |
| <td>15ns<span class="speedup"></span></td><td>2µs<span class="speedup"> (104.8x slower)</span></td><td>1µs<span class="speedup"> (71.3x slower)</span></td><td>1µs<span class="speedup"> (78.7x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector tag (10000 elem)</strong></td> | |
| <td>16ns<span class="speedup"></span></td><td>16µs<span class="speedup"> (987.0x slower)</span></td><td>13µs<span class="speedup"> (815.6x slower)</span></td><td>20µs<span class="speedup"> (1239.3x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="category"> | |
| <h2>Class Queries</h2> | |
| <div class="chart-container"> | |
| <canvas id="chart-2"></canvas> | |
| </div> | |
| <table class="stats-table"> | |
| <thead> | |
| <tr> | |
| <th>Benchmark</th> | |
| <th>Zig</th><th>Chromium</th><th>Firefox</th><th>WebKit</th> | |
| <th>Winner</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>Pure query: getElementsByClassName (100 elem)</strong></td> | |
| <td>5µs<span class="speedup"> (73.5x slower)</span></td><td>101ns<span class="speedup"> (1.5x slower)</span></td><td>147ns<span class="speedup"> (2.2x slower)</span></td><td>68ns<span class="speedup"></span></td> | |
| <td class="winner">WebKit</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementsByClassName (1000 elem)</strong></td> | |
| <td>6µs<span class="speedup"> (90.9x slower)</span></td><td>91ns<span class="speedup"> (1.4x slower)</span></td><td>156ns<span class="speedup"> (2.4x slower)</span></td><td>66ns<span class="speedup"></span></td> | |
| <td class="winner">WebKit</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: getElementsByClassName (10000 elem)</strong></td> | |
| <td>7µs<span class="speedup"> (104.5x slower)</span></td><td>94ns<span class="speedup"> (1.4x slower)</span></td><td>154ns<span class="speedup"> (2.3x slower)</span></td><td>67ns<span class="speedup"></span></td> | |
| <td class="winner">WebKit</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector .class (100 elem)</strong></td> | |
| <td>15ns<span class="speedup"></span></td><td>87ns<span class="speedup"> (5.8x slower)</span></td><td>180ns<span class="speedup"> (12.0x slower)</span></td><td>110ns<span class="speedup"> (7.3x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector .class (1000 elem)</strong></td> | |
| <td>15ns<span class="speedup"></span></td><td>86ns<span class="speedup"> (5.7x slower)</span></td><td>180ns<span class="speedup"> (12.0x slower)</span></td><td>110ns<span class="speedup"> (7.3x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pure query: querySelector .class (10000 elem)</strong></td> | |
| <td>15ns<span class="speedup"></span></td><td>79ns<span class="speedup"> (5.3x slower)</span></td><td>180ns<span class="speedup"> (12.0x slower)</span></td><td>120ns<span class="speedup"> (8.0x slower)</span></td> | |
| <td class="winner">Zig</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="category"> | |
| <h2>Complex Queries</h2> | |
| <div class="chart-container"> | |
| <canvas id="chart-3"></canvas> | |
| </div> | |
| <table class="stats-table"> | |
| <thead> | |
| <tr> | |
| <th>Benchmark</th> | |
| <th>Zig</th><th>Chromium</th><th>Firefox</th><th>WebKit</th> | |
| <th>Winner</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>querySelector: Small DOM (100)</strong></td> | |
| <td>37µs<span class="speedup"> (1.9x slower)</span></td><td>19µs<span class="speedup"></span></td><td>29µs<span class="speedup"> (1.5x slower)</span></td><td>24µs<span class="speedup"> (1.3x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>querySelector: Medium DOM (1000)</strong></td> | |
| <td>226µs<span class="speedup"> (1.4x slower)</span></td><td>161µs<span class="speedup"></span></td><td>265µs<span class="speedup"> (1.7x slower)</span></td><td>236µs<span class="speedup"> (1.5x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>querySelector: Large DOM (10000)</strong></td> | |
| <td>11ms<span class="speedup"> (7.4x slower)</span></td><td>1ms<span class="speedup"></span></td><td>3ms<span class="speedup"> (1.8x slower)</span></td><td>2ms<span class="speedup"> (1.4x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>querySelector: Class selector</strong></td> | |
| <td>224µs<span class="speedup"> (1.4x slower)</span></td><td>159µs<span class="speedup"></span></td><td>255µs<span class="speedup"> (1.6x slower)</span></td><td>206µs<span class="speedup"> (1.3x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>SPA: Repeated queries (1000x)</strong></td> | |
| <td>79µs<span class="speedup"> (1.5x slower)</span></td><td>54µs<span class="speedup"></span></td><td>98µs<span class="speedup"> (1.8x slower)</span></td><td>174µs<span class="speedup"> (3.2x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| <tr> | |
| <td><strong>SPA: Cold vs Hot cache (100x)</strong></td> | |
| <td>452µs<span class="speedup"> (1.9x slower)</span></td><td>240µs<span class="speedup"></span></td><td>400µs<span class="speedup"> (1.7x slower)</span></td><td>371µs<span class="speedup"> (1.5x slower)</span></td> | |
| <td class="winner">Chromium</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <footer> | |
| <p>Generated: 10/17/2025, 3:28:10 PM</p> | |
| <p>Zig DOM Implementation - Benchmark Report</p> | |
| </footer> | |
| </div> | |
| <script> | |
| const implementations = ["Zig","Chromium","Firefox","WebKit"]; | |
| const colors = { | |
| 'Zig': '#f9a825', | |
| 'Chromium': '#4285f4', | |
| 'Firefox': '#ff6611', | |
| 'WebKit': '#00aaff' | |
| }; | |
| const chartData = [{"category":"ID Queries","benchmarks":[{"name":"getElementById: Small DOM (100)","data":[29000,13944.22310756972,25819.265143992056,24875.62189054715]},{"name":"getElementById: Medium DOM (1000)","data":[216000,143099.99990463257,273631.8407960199,253240.27916251245]},{"name":"getElementById: Large DOM (10000)","data":[11000000,1496153.847529338,2816513.7614678903,2609999.9999999977]},{"name":"Pure query: getElementById (100 elem)","data":[5,93.29999995231628,101.99938800367198,76.999923000077]},{"name":"Pure query: getElementById (1000 elem)","data":[5,92.89962849685344,99.99920000639996,71.99942400460797]},{"name":"Pure query: getElementById (10000 elem)","data":[4,96.79912876015743,102.99979400041201,70.999787000639]},{"name":"Pure query: querySelector #id (100 elem)","data":[13,101.99388084398652,169.9932002719891,159.99200039998001]},{"name":"Pure query: querySelector #id (1000 elem)","data":[14,93.9943612919968,169.99660006799863,149.99850001500212]},{"name":"Pure query: querySelector #id (10000 elem)","data":[15,96.99224109754935,169.9949001529954,169.98470137687607]}]},{"category":"Tag Queries","benchmarks":[{"name":"Pure query: getElementsByTagName (100 elem)","data":[5000,89.49928400572796,120.99987900012101,73.99948200362597]},{"name":"Pure query: getElementsByTagName (1000 elem)","data":[5000,85.69940015188266,122.999754000492,72.999854000292]},{"name":"Pure query: getElementsByTagName (10000 elem)","data":[7000,83.89958059746444,136.999863000137,129.9988300105299]},{"name":"Pure query: querySelector tag (100 elem)","data":[15,205.99999904632568,289.9739023487886,239.97840194382505]},{"name":"Pure query: querySelector tag (1000 elem)","data":[15,1571.9842806340307,1069.9144068474523,1179.9528018879246]},{"name":"Pure query: querySelector tag (10000 elem)","data":[16,15792.000000476837,13050,19828.6119971602]}]},{"category":"Class Queries","benchmarks":[{"name":"Pure query: getElementsByClassName (100 elem)","data":[5000,101.49908650822142,146.999412002352,67.999932000068]},{"name":"Pure query: getElementsByClassName (1000 elem)","data":[6000,90.99990900009101,155.999532001404,65.99940600534595]},{"name":"Pure query: getElementsByClassName (10000 elem)","data":[7000,93.89953035929705,153.99907600554397,66.999933000067]},{"name":"Pure query: querySelector .class (100 elem)","data":[15,87.00000047683716,179.9982000179998,110]},{"name":"Pure query: querySelector .class (1000 elem)","data":[15,85.99225974294882,180,109.99890001099989]},{"name":"Pure query: querySelector .class (10000 elem)","data":[15,78.99999856948853,179.99280028798847,119.99160058795884]}]},{"category":"Complex Queries","benchmarks":[{"name":"querySelector: Small DOM (100)","data":[37000,19127.84954483138,28769.84126984127,23928.215353938183]},{"name":"querySelector: Medium DOM (1000)","data":[226000,160678.64271457086,265469.0618762475,236000]},{"name":"querySelector: Large DOM (10000)","data":[11000000,1492233.007856943,2627450.9803921566,2037735.8490566039]},{"name":"querySelector: Class selector","data":[224000,158771.0605031553,254980.0796812749,205765.40755467195]},{"name":"SPA: Repeated queries (1000x)","data":[79000,53646.353693989724,97902.0979020979,173956.26242544732]},{"name":"SPA: Cold vs Hot cache (100x)","data":[452000,239814.8156978466,400000,371428.57142857247]}]}]; | |
| // Create charts | |
| chartData.forEach((category, index) => { | |
| if (category.benchmarks.length === 0) return; | |
| const ctx = document.getElementById(`chart-${index}`); | |
| const datasets = implementations.map((impl, i) => ({ | |
| label: impl, | |
| data: category.benchmarks.map(b => b.data[i]), | |
| backgroundColor: colors[impl] || `hsl(${i * 60}, 70%, 60%)`, | |
| borderColor: colors[impl] || `hsl(${i * 60}, 70%, 50%)`, | |
| borderWidth: 2 | |
| })); | |
| new Chart(ctx, { | |
| type: 'bar', | |
| data: { | |
| labels: category.benchmarks.map(b => b.name.replace(/Pure query: /, '').replace(/ \(\d+ elem\)/, '')), | |
| datasets: datasets | |
| }, | |
| options: { | |
| responsive: true, | |
| maintainAspectRatio: false, | |
| plugins: { | |
| title: { | |
| display: false | |
| }, | |
| legend: { | |
| position: 'top', | |
| labels: { | |
| font: { | |
| size: 12, | |
| weight: 600 | |
| }, | |
| padding: 15 | |
| } | |
| }, | |
| tooltip: { | |
| callbacks: { | |
| label: function(context) { | |
| let value = context.parsed.y; | |
| if (value === null) return ''; | |
| let display; | |
| if (value < 1000) { | |
| display = Math.round(value) + 'ns'; | |
| } else if (value < 1000000) { | |
| display = Math.round(value / 1000) + 'µs'; | |
| } else { | |
| display = Math.round(value / 1000000) + 'ms'; | |
| } | |
| return context.dataset.label + ': ' + display; | |
| } | |
| } | |
| } | |
| }, | |
| scales: { | |
| y: { | |
| type: 'logarithmic', | |
| title: { | |
| display: true, | |
| text: 'Time per Operation (ns, log scale)', | |
| font: { | |
| size: 14, | |
| weight: 600 | |
| } | |
| }, | |
| ticks: { | |
| callback: function(value) { | |
| if (value < 1000) return value + 'ns'; | |
| if (value < 1000000) return (value / 1000) + 'µs'; | |
| return (value / 1000000) + 'ms'; | |
| } | |
| } | |
| }, | |
| x: { | |
| ticks: { | |
| font: { | |
| size: 11 | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment