diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 529a7242443820..2d901824335145 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -267,14 +267,20 @@ Refer to the documentation of the individual functions for more information. .. versionadded:: 3.4 -.. function:: z85encode(s) +.. function:: z85encode(s, pad=False) Encode the :term:`bytes-like object` *s* using Z85 (as used in ZeroMQ) and return the encoded :class:`bytes`. See `Z85 specification `_ for more information. + If *pad* is true, the input is padded with ``b'\0'`` so its length is a + multiple of 4 bytes before encoding. + .. versionadded:: 3.13 + .. versionchanged:: next + The *pad* parameter was added. + .. function:: z85decode(s) diff --git a/Doc/library/profiling.sampling.rst b/Doc/library/profiling.sampling.rst index 370bbcd3242526..dae67cca66d9b4 100644 --- a/Doc/library/profiling.sampling.rst +++ b/Doc/library/profiling.sampling.rst @@ -241,8 +241,8 @@ is unaware it is being profiled. When profiling production systems, keep these guidelines in mind: Start with shorter durations (10-30 seconds) to get quick results, then extend -if you need more statistical accuracy. The default 10-second duration is usually -sufficient to identify major hotspots. +if you need more statistical accuracy. By default, profiling runs until the +target process completes, which is usually sufficient to identify major hotspots. If possible, profile during representative load rather than peak traffic. Profiles collected during normal operation are easier to interpret than those @@ -329,7 +329,7 @@ The default configuration works well for most use cases: * - Default for ``--sampling-rate`` / ``-r`` - 1 kHz * - Default for ``--duration`` / ``-d`` - - 10 seconds + - Run to completion * - Default for ``--all-threads`` / ``-a`` - Main thread only * - Default for ``--native`` @@ -363,15 +363,14 @@ cost of slightly higher profiler CPU usage. Lower rates reduce profiler overhead but may miss short-lived functions. For most applications, the default rate provides a good balance between accuracy and overhead. -The :option:`--duration` option (:option:`-d`) sets how long to profile in seconds. The -default is 10 seconds:: +The :option:`--duration` option (:option:`-d`) sets how long to profile in seconds. By +default, profiling continues until the target process exits or is interrupted:: python -m profiling.sampling run -d 60 script.py -Longer durations collect more samples and produce more statistically reliable -results, especially for code paths that execute infrequently. When profiling -a program that runs for a fixed time, you may want to set the duration to -match or exceed the expected runtime. +Specifying a duration is useful when attaching to long-running processes or when +you want to limit profiling to a specific time window. When profiling a script, +the default behavior of running to completion is usually what you want. Thread selection @@ -1394,7 +1393,7 @@ Sampling options .. option:: -d , --duration - Profiling duration in seconds. Default: 10. + Profiling duration in seconds. Default: run to completion. .. option:: -a, --all-threads diff --git a/Lib/base64.py b/Lib/base64.py index 341bf8eaf1891e..c2fdee8eab9690 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -508,9 +508,9 @@ def b85decode(b): ) _z85_encode_translation = bytes.maketrans(_b85alphabet, _z85alphabet) -def z85encode(s): +def z85encode(s, pad=False): """Encode bytes-like object b in z85 format and return a bytes object.""" - return b85encode(s).translate(_z85_encode_translation) + return b85encode(s, pad).translate(_z85_encode_translation) def z85decode(s): """Decode the z85-encoded bytes-like object or ASCII string b diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css index 03eb2274d23e68..24e67bedee5242 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.css @@ -346,10 +346,10 @@ body.resizing-sidebar { position: relative; } -.summary-card:nth-child(1) { --i: 0; --card-color: 55, 118, 171; } -.summary-card:nth-child(2) { --i: 1; --card-color: 40, 167, 69; } -.summary-card:nth-child(3) { --i: 2; --card-color: 255, 193, 7; } -.summary-card:nth-child(4) { --i: 3; --card-color: 111, 66, 193; } +.summary-card:nth-child(1) { --i: 0; --card-color: var(--card-blue); } +.summary-card:nth-child(2) { --i: 1; --card-color: var(--card-green); } +.summary-card:nth-child(3) { --i: 2; --card-color: var(--card-yellow); } +.summary-card:nth-child(4) { --i: 3; --card-color: var(--card-purple); } .summary-card:hover { border-color: rgba(var(--card-color), 0.6); @@ -405,21 +405,18 @@ body.resizing-sidebar { text-overflow: ellipsis; } -/* Efficiency Bar */ -.efficiency-section { - margin-top: 10px; - padding-top: 10px; - border-top: 1px solid var(--border); -} +/* -------------------------------------------------------------------------- + Progress Bars + -------------------------------------------------------------------------- */ -.efficiency-header { +.bar-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; } -.efficiency-label { +.bar-label { font-size: 9px; font-weight: 600; color: var(--text-secondary); @@ -427,21 +424,21 @@ body.resizing-sidebar { letter-spacing: 0.2px; } -.efficiency-value { +.bar-value { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--accent); } -.efficiency-bar { +.bar { height: 6px; background: var(--bg-tertiary); border-radius: 3px; overflow: hidden; } -.efficiency-fill { +.bar-fill { height: 100%; background: linear-gradient(90deg, #28a745 0%, #20c997 50%, #17a2b8 100%); border-radius: 3px; @@ -450,7 +447,7 @@ body.resizing-sidebar { overflow: hidden; } -.efficiency-fill::after { +.bar-fill::after { content: ''; position: absolute; top: 0; @@ -467,68 +464,56 @@ body.resizing-sidebar { } /* -------------------------------------------------------------------------- - Thread Stats Grid (in Sidebar) + Efficiency Section Container + -------------------------------------------------------------------------- */ + +.efficiency-section { + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--border); +} + +/* -------------------------------------------------------------------------- + Thread Stats Progress Bars (in Sidebar) -------------------------------------------------------------------------- */ .thread-stats-section { display: block; } -.stats-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; +.stats-container { + display: flex; + flex-direction: column; + gap: 10px; } -.stat-tile { - background: var(--bg-primary); - border-radius: 8px; - padding: 10px; - text-align: center; - border: 2px solid var(--border); - transition: all var(--transition-fast); +.stat-item { animation: fadeIn 0.4s ease-out backwards; animation-delay: calc(var(--i, 0) * 0.05s); } -.stat-tile:nth-child(1) { --i: 0; } -.stat-tile:nth-child(2) { --i: 1; } -.stat-tile:nth-child(3) { --i: 2; } -.stat-tile:nth-child(4) { --i: 3; } +.stat-item:nth-child(1) { --i: 0; } +.stat-item:nth-child(2) { --i: 1; } +.stat-item:nth-child(3) { --i: 2; } +.stat-item:nth-child(4) { --i: 3; } +.stat-item:nth-child(5) { --i: 4; } -.stat-tile:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-sm); +/* Color variants for bar-fill */ +.bar-fill--green { + background: linear-gradient(90deg, #28a745 0%, #20c997 100%); } -.stat-tile-value { - font-family: var(--font-mono); - font-size: 16px; - font-weight: 700; - color: var(--text-primary); - line-height: 1.2; +.bar-fill--yellow { + background: linear-gradient(90deg, #ffc107 0%, #ffdb4d 100%); } -.stat-tile-label { - font-size: 9px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.3px; - color: var(--text-muted); - margin-top: 2px; +.bar-fill--purple { + background: linear-gradient(90deg, #6f42c1 0%, #9b6dd6 100%); } -/* Stat tile color variants */ -.stat-tile--green { --tile-color: 40, 167, 69; --tile-text: #28a745; } -.stat-tile--red { --tile-color: 220, 53, 69; --tile-text: #dc3545; } -.stat-tile--yellow { --tile-color: 255, 193, 7; --tile-text: #d39e00; } -.stat-tile--purple { --tile-color: 111, 66, 193; --tile-text: #6f42c1; } - -.stat-tile[class*="--"] { - border-color: rgba(var(--tile-color), 0.4); - background: linear-gradient(135deg, rgba(var(--tile-color), 0.08) 0%, var(--bg-primary) 100%); +.bar-fill--red { + background: linear-gradient(90deg, #dc3545 0%, #ff6b7a 100%); } -.stat-tile[class*="--"] .stat-tile-value { color: var(--tile-text); } /* -------------------------------------------------------------------------- Hotspot Cards @@ -985,10 +970,6 @@ body.resizing-sidebar { .brand-info { display: none; } - - .stats-grid { - grid-template-columns: 1fr; - } } /* -------------------------------------------------------------------------- diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js index 17fd95af859587..1a51802ffefac7 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js @@ -742,24 +742,38 @@ function populateThreadStats(data, selectedThreadId = null) { if (gilReleasedStat) gilReleasedStat.style.display = 'block'; if (gilWaitingStat) gilWaitingStat.style.display = 'block'; + const gilHeldPct = threadStats.has_gil_pct || 0; const gilHeldPctElem = document.getElementById('gil-held-pct'); - if (gilHeldPctElem) gilHeldPctElem.textContent = `${(threadStats.has_gil_pct || 0).toFixed(1)}%`; + if (gilHeldPctElem) gilHeldPctElem.textContent = `${gilHeldPct.toFixed(1)}%`; + const gilHeldFill = document.getElementById('gil-held-fill'); + if (gilHeldFill) gilHeldFill.style.width = `${gilHeldPct}%`; - const gilReleasedPctElem = document.getElementById('gil-released-pct'); // GIL Released = not holding GIL and not waiting for it const gilReleasedPct = Math.max(0, 100 - (threadStats.has_gil_pct || 0) - (threadStats.gil_requested_pct || 0)); + const gilReleasedPctElem = document.getElementById('gil-released-pct'); if (gilReleasedPctElem) gilReleasedPctElem.textContent = `${gilReleasedPct.toFixed(1)}%`; + const gilReleasedFill = document.getElementById('gil-released-fill'); + if (gilReleasedFill) gilReleasedFill.style.width = `${gilReleasedPct}%`; + const gilWaitingPct = threadStats.gil_requested_pct || 0; const gilWaitingPctElem = document.getElementById('gil-waiting-pct'); - if (gilWaitingPctElem) gilWaitingPctElem.textContent = `${(threadStats.gil_requested_pct || 0).toFixed(1)}%`; + if (gilWaitingPctElem) gilWaitingPctElem.textContent = `${gilWaitingPct.toFixed(1)}%`; + const gilWaitingFill = document.getElementById('gil-waiting-fill'); + if (gilWaitingFill) gilWaitingFill.style.width = `${gilWaitingPct}%`; } + const gcPct = threadStats.gc_pct || 0; const gcPctElem = document.getElementById('gc-pct'); - if (gcPctElem) gcPctElem.textContent = `${(threadStats.gc_pct || 0).toFixed(1)}%`; + if (gcPctElem) gcPctElem.textContent = `${gcPct.toFixed(1)}%`; + const gcFill = document.getElementById('gc-fill'); + if (gcFill) gcFill.style.width = `${gcPct}%`; // Exception stats + const excPct = threadStats.has_exception_pct || 0; const excPctElem = document.getElementById('exc-pct'); - if (excPctElem) excPctElem.textContent = `${(threadStats.has_exception_pct || 0).toFixed(1)}%`; + if (excPctElem) excPctElem.textContent = `${excPct.toFixed(1)}%`; + const excFill = document.getElementById('exc-fill'); + if (excFill) excFill.style.width = `${excPct}%`; } // ============================================================================ diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html b/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html index 936c9adfc8c519..195a555d68e98b 100644 --- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html +++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html @@ -159,21 +159,21 @@

Profile Summary