https://github.com/python/cpython/commit/cbc0851ada9c5bc4018fb5075c82abe2ef4fc4cf
commit: cbc0851ada9c5bc4018fb5075c82abe2ef4fc4cf
branch: main
author: ivonastojanovic <[email protected]>
committer: pablogsal <[email protected]>
date: 2025-12-18T11:43:39Z
summary:

gh-138122: Improve bytecode panel (#142910)

The bytecode panel appears when a user generates a heatmap with
--opcodes and clicks the button to unfold a line and display the
bytecode instructions. Currently, an empty space appears on the
left where the line number, self, and total columns are displayed.
This area should instead extend those columns, rather than leaving
a gap.

files:
M Lib/profiling/sampling/_heatmap_assets/heatmap.css
M Lib/profiling/sampling/_heatmap_assets/heatmap.js
M Lib/profiling/sampling/heatmap_collector.py

diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.css 
b/Lib/profiling/sampling/_heatmap_assets/heatmap.css
index 65a13d7245d5c4..9999cd6760fd49 100644
--- a/Lib/profiling/sampling/_heatmap_assets/heatmap.css
+++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.css
@@ -1141,6 +1141,10 @@
   .line-samples-cumulative {
     padding: 0 4px;
   }
+
+  .bytecode-panel {
+    margin: 8px 10px 8px 160px;
+  }
 }
 
 .bytecode-toggle {
@@ -1172,13 +1176,77 @@
 }
 
 .bytecode-panel {
-  margin-left: 90px;
-  padding: 8px 15px;
-  background: var(--bg-secondary);
-  border-left: 3px solid var(--accent);
+  background: var(--bg-primary);
+  border: 1px solid var(--border);
+  border-radius: 8px;
+  box-shadow: var(--shadow-md);
   font-family: var(--font-mono);
   font-size: 12px;
-  margin-bottom: 4px;
+  color: var(--text-primary);
+  line-height: 1.5;
+  word-wrap: break-word;
+  overflow-wrap: break-word;
+  padding: 0;
+  margin: 8px 10px 8px 250px;
+  position: relative;
+  z-index: 1;
+  overflow-y: auto;
+  max-height: 500px;
+  flex: 1;
+  transition: padding 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.bytecode-panel.expanded {
+  padding: 14px;
+}
+
+.bytecode-wrapper {
+  position: relative;
+  display: flex;
+  overflow: visible;
+  max-height: 0;
+  opacity: 0;
+  transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s 
ease-in-out;
+}
+
+.bytecode-wrapper.expanded {
+  max-height: 600px;
+  opacity: 1;
+  transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s 
ease-in-out;
+}
+
+/* Column backdrop matching table header columns (line/self/total) */
+.bytecode-columns {
+  display: none;
+  position: absolute;
+  left: 0;
+  overflow: hidden;
+  pointer-events: none;
+  z-index: 0;
+}
+
+.bytecode-wrapper.expanded .bytecode-columns {
+  display: flex;
+  top: 0;
+  bottom: 0;
+}
+
+.bytecode-panel::-webkit-scrollbar {
+  width: 8px;
+}
+
+.bytecode-panel::-webkit-scrollbar-track {
+  background: var(--bg-secondary);
+  border-radius: 4px;
+}
+
+.bytecode-panel::-webkit-scrollbar-thumb {
+  background: var(--border);
+  border-radius: 4px;
+}
+
+.bytecode-panel::-webkit-scrollbar-thumb:hover {
+  background: var(--text-muted);
 }
 
 /* Specialization summary bar */
diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js 
b/Lib/profiling/sampling/_heatmap_assets/heatmap.js
index 8ac4ef43e53b37..d6a91ef290309b 100644
--- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js
+++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js
@@ -542,20 +542,23 @@ function toggleBytecode(button) {
     const lineId = lineDiv.id;
     const lineNum = lineId.replace('line-', '');
     const panel = document.getElementById(`bytecode-${lineNum}`);
+    const wrapper = document.getElementById(`bytecode-wrapper-${lineNum}`);
 
-    if (!panel) return;
+    if (!panel || !wrapper) return;
 
-    const isExpanded = panel.style.display !== 'none';
+    const isExpanded = panel.classList.contains('expanded');
 
     if (isExpanded) {
-        panel.style.display = 'none';
+        panel.classList.remove('expanded');
+        wrapper.classList.remove('expanded');
         button.classList.remove('expanded');
         button.innerHTML = '&#9654;';  // Right arrow
     } else {
         if (!panel.dataset.populated) {
             populateBytecodePanel(panel, button);
         }
-        panel.style.display = 'block';
+        panel.classList.add('expanded');
+        wrapper.classList.add('expanded');
         button.classList.add('expanded');
         button.innerHTML = '&#9660;';  // Down arrow
     }
diff --git a/Lib/profiling/sampling/heatmap_collector.py 
b/Lib/profiling/sampling/heatmap_collector.py
index 5b4c89283be08c..e6701901aa385c 100644
--- a/Lib/profiling/sampling/heatmap_collector.py
+++ b/Lib/profiling/sampling/heatmap_collector.py
@@ -978,7 +978,17 @@ def _build_line_html(self, line_num: int, line_content: 
str,
                 f'data-spec-pct="{spec_pct}" '
                 f'onclick="toggleBytecode(this)" title="Show 
bytecode">&#9654;</button>'
             )
-            bytecode_panel_html = f'        <div class="bytecode-panel" 
id="bytecode-{line_num}" style="display:none;"></div>\n'
+            # Wrapper contains columns + content panel
+            bytecode_panel_html = (
+                f'        <div class="bytecode-wrapper" 
id="bytecode-wrapper-{line_num}">\n'
+                f'            <div class="bytecode-columns">'
+                f'<div class="line-number"></div>'
+                f'<div class="line-samples-self"></div>'
+                f'<div class="line-samples-cumulative"></div>'
+                f'</div>\n'
+                f'            <div class="bytecode-panel" 
id="bytecode-{line_num}"></div>\n'
+                f'        </div>\n'
+            )
         elif self.opcodes_enabled:
             # Add invisible spacer to maintain consistent indentation when 
opcodes are enabled
             bytecode_btn_html = '<div class="bytecode-spacer"></div>'

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to