https://github.com/python/cpython/commit/d4dc3dd9aab6e860ea29e3bd133147a3f795cf60
commit: d4dc3dd9aab6e860ea29e3bd133147a3f795cf60
branch: main
author: László Kiss Kollár <[email protected]>
committer: pablogsal <[email protected]>
date: 2025-12-24T13:46:33Z
summary:

gh-138122: Replace --interval with --sampling-rate (#143085)

files:
M Doc/library/profiling.sampling.rst
M Lib/profiling/sampling/_child_monitor.py
M Lib/profiling/sampling/_sync_coordinator.py
M Lib/profiling/sampling/cli.py
M Lib/profiling/sampling/constants.py
M Lib/profiling/sampling/live_collector/__init__.py
M Lib/profiling/sampling/live_collector/collector.py
M Lib/profiling/sampling/live_collector/constants.py
M Lib/profiling/sampling/live_collector/widgets.py
M Lib/profiling/sampling/pstats_collector.py
M Lib/test/test_profiling/test_sampling_profiler/test_advanced.py
M Lib/test/test_profiling/test_sampling_profiler/test_children.py
M Lib/test/test_profiling/test_sampling_profiler/test_cli.py
M 
Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py
M Lib/test/test_profiling/test_sampling_profiler/test_modes.py

diff --git a/Doc/library/profiling.sampling.rst 
b/Doc/library/profiling.sampling.rst
index b5e6a2c7a0ed8e..370bbcd3242526 100644
--- a/Doc/library/profiling.sampling.rst
+++ b/Doc/library/profiling.sampling.rst
@@ -53,7 +53,7 @@ counts**, not direct measurements. Tachyon counts how many 
times each function
 appears in the collected samples, then multiplies by the sampling interval to
 estimate time.
 
-For example, with a 100 microsecond sampling interval over a 10-second profile,
+For example, with a 10 kHz sampling rate over a 10-second profile,
 Tachyon collects approximately 100,000 samples. If a function appears in 5,000
 samples (5% of total), Tachyon estimates it consumed 5% of the 10-second
 duration, or about 500 milliseconds. This is a statistical estimate, not a
@@ -142,7 +142,7 @@ Use live mode for real-time monitoring (press ``q`` to 
quit)::
 
 Profile for 60 seconds with a faster sampling rate::
 
-   python -m profiling.sampling run -d 60 -i 50 script.py
+   python -m profiling.sampling run -d 60 -r 20khz script.py
 
 Generate a line-by-line heatmap::
 
@@ -326,8 +326,8 @@ The default configuration works well for most use cases:
 
    * - Option
      - Default
-   * - Default for ``--interval`` / ``-i``
-     - 100 µs between samples (~10,000 samples/sec)
+   * - Default for ``--sampling-rate`` / ``-r``
+     - 1 kHz
    * - Default for ``--duration`` / ``-d``
      - 10 seconds
    * - Default for ``--all-threads`` / ``-a``
@@ -346,23 +346,22 @@ The default configuration works well for most use cases:
      - Disabled (non-blocking sampling)
 
 
-Sampling interval and duration
-------------------------------
+Sampling rate and duration
+--------------------------
 
-The two most fundamental parameters are the sampling interval and duration.
+The two most fundamental parameters are the sampling rate and duration.
 Together, these determine how many samples will be collected during a profiling
 session.
 
-The :option:`--interval` option (:option:`-i`) sets the time between samples in
-microseconds. The default is 100 microseconds, which produces approximately
-10,000 samples per second::
+The :option:`--sampling-rate` option (:option:`-r`) sets how frequently samples
+are collected. The default is 1 kHz (10,000 samples per second)::
 
-   python -m profiling.sampling run -i 50 script.py
+   python -m profiling.sampling run -r 20khz script.py
 
-Lower intervals capture more samples and provide finer-grained data at the
-cost of slightly higher profiler CPU usage. Higher intervals reduce profiler
+Higher rates capture more samples and provide finer-grained data at the
+cost of slightly higher profiler CPU usage. Lower rates reduce profiler
 overhead but may miss short-lived functions. For most applications, the
-default interval provides a good balance between accuracy and overhead.
+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::
@@ -573,9 +572,9 @@ appended:
 - For pstats format (which defaults to stdout), subprocesses produce files like
   ``profile_12345.pstats``
 
-The subprocess profilers inherit most sampling options from the parent 
(interval,
-duration, thread selection, native frames, GC frames, async-aware mode, and
-output format). All Python descendant processes are profiled recursively,
+The subprocess profilers inherit most sampling options from the parent 
(sampling
+rate, duration, thread selection, native frames, GC frames, async-aware mode,
+and output format). All Python descendant processes are profiled recursively,
 including grandchildren and further descendants.
 
 Subprocess detection works by periodically scanning for new descendants of
@@ -1389,9 +1388,9 @@ Global options
 Sampling options
 ----------------
 
-.. option:: -i <microseconds>, --interval <microseconds>
+.. option:: -r <rate>, --sampling-rate <rate>
 
-   Sampling interval in microseconds. Default: 100.
+   Sampling rate (for example, ``10000``, ``10khz``, ``10k``). Default: 
``1khz``.
 
 .. option:: -d <seconds>, --duration <seconds>
 
diff --git a/Lib/profiling/sampling/_child_monitor.py 
b/Lib/profiling/sampling/_child_monitor.py
index e06c550d938b13..ec56f75719f9d1 100644
--- a/Lib/profiling/sampling/_child_monitor.py
+++ b/Lib/profiling/sampling/_child_monitor.py
@@ -16,7 +16,7 @@
 _CHILD_POLL_INTERVAL_SEC = 0.1
 
 # Default timeout for waiting on child profilers
-_DEFAULT_WAIT_TIMEOUT = 30.0
+_DEFAULT_WAIT_TIMEOUT_SEC = 30.0
 
 # Maximum number of child profilers to spawn (prevents resource exhaustion)
 _MAX_CHILD_PROFILERS = 100
@@ -138,7 +138,7 @@ def spawned_profilers(self):
         with self._lock:
             return list(self._spawned_profilers)
 
-    def wait_for_profilers(self, timeout=_DEFAULT_WAIT_TIMEOUT):
+    def wait_for_profilers(self, timeout=_DEFAULT_WAIT_TIMEOUT_SEC):
         """
         Wait for all spawned child profilers to complete.
 
diff --git a/Lib/profiling/sampling/_sync_coordinator.py 
b/Lib/profiling/sampling/_sync_coordinator.py
index 1a4af42588a3f5..63d057043f0416 100644
--- a/Lib/profiling/sampling/_sync_coordinator.py
+++ b/Lib/profiling/sampling/_sync_coordinator.py
@@ -73,8 +73,8 @@ def _validate_arguments(args: List[str]) -> tuple[int, str, 
List[str]]:
 
 # Constants for socket communication
 _MAX_RETRIES = 3
-_INITIAL_RETRY_DELAY = 0.1
-_SOCKET_TIMEOUT = 2.0
+_INITIAL_RETRY_DELAY_SEC = 0.1
+_SOCKET_TIMEOUT_SEC = 2.0
 _READY_MESSAGE = b"ready"
 
 
@@ -93,14 +93,14 @@ def _signal_readiness(sync_port: int) -> None:
     for attempt in range(_MAX_RETRIES):
         try:
             # Use context manager for automatic cleanup
-            with socket.create_connection(("127.0.0.1", sync_port), 
timeout=_SOCKET_TIMEOUT) as sock:
+            with socket.create_connection(("127.0.0.1", sync_port), 
timeout=_SOCKET_TIMEOUT_SEC) as sock:
                 sock.send(_READY_MESSAGE)
                 return
         except (socket.error, OSError) as e:
             last_error = e
             if attempt < _MAX_RETRIES - 1:
                 # Exponential backoff before retry
-                time.sleep(_INITIAL_RETRY_DELAY * (2 ** attempt))
+                time.sleep(_INITIAL_RETRY_DELAY_SEC * (2 ** attempt))
 
     # If we get here, all retries failed
     raise SyncError(f"Failed to signal readiness after {_MAX_RETRIES} 
attempts: {last_error}") from last_error
diff --git a/Lib/profiling/sampling/cli.py b/Lib/profiling/sampling/cli.py
index ccd6e954d79698..9e60961943a8d0 100644
--- a/Lib/profiling/sampling/cli.py
+++ b/Lib/profiling/sampling/cli.py
@@ -4,6 +4,7 @@
 import importlib.util
 import locale
 import os
+import re
 import selectors
 import socket
 import subprocess
@@ -20,6 +21,7 @@
 from .binary_collector import BinaryCollector
 from .binary_reader import BinaryReader
 from .constants import (
+    MICROSECONDS_PER_SECOND,
     PROFILING_MODE_ALL,
     PROFILING_MODE_WALL,
     PROFILING_MODE_CPU,
@@ -66,8 +68,8 @@ class CustomFormatter(
 
 
 # Constants for socket synchronization
-_SYNC_TIMEOUT = 5.0
-_PROCESS_KILL_TIMEOUT = 2.0
+_SYNC_TIMEOUT_SEC = 5.0
+_PROCESS_KILL_TIMEOUT_SEC = 2.0
 _READY_MESSAGE = b"ready"
 _RECV_BUFFER_SIZE = 1024
 
@@ -116,7 +118,8 @@ def _build_child_profiler_args(args):
     child_args = []
 
     # Sampling options
-    child_args.extend(["-i", str(args.interval)])
+    hz = MICROSECONDS_PER_SECOND // args.sample_interval_usec
+    child_args.extend(["-r", str(hz)])
     child_args.extend(["-d", str(args.duration)])
 
     if args.all_threads:
@@ -239,7 +242,7 @@ def _run_with_sync(original_cmd, suppress_output=False):
         sync_sock.bind(("127.0.0.1", 0))  # Let OS choose a free port
         sync_port = sync_sock.getsockname()[1]
         sync_sock.listen(1)
-        sync_sock.settimeout(_SYNC_TIMEOUT)
+        sync_sock.settimeout(_SYNC_TIMEOUT_SEC)
 
         # Get current working directory to preserve it
         cwd = os.getcwd()
@@ -268,7 +271,7 @@ def _run_with_sync(original_cmd, suppress_output=False):
         process = subprocess.Popen(cmd, **popen_kwargs)
 
         try:
-            _wait_for_ready_signal(sync_sock, process, _SYNC_TIMEOUT)
+            _wait_for_ready_signal(sync_sock, process, _SYNC_TIMEOUT_SEC)
 
             # Close stderr pipe if we were capturing it
             if process.stderr:
@@ -279,7 +282,7 @@ def _run_with_sync(original_cmd, suppress_output=False):
             if process.poll() is None:
                 process.terminate()
                 try:
-                    process.wait(timeout=_PROCESS_KILL_TIMEOUT)
+                    process.wait(timeout=_PROCESS_KILL_TIMEOUT_SEC)
                 except subprocess.TimeoutExpired:
                     process.kill()
                     process.wait()
@@ -290,16 +293,64 @@ def _run_with_sync(original_cmd, suppress_output=False):
         return process
 
 
+_RATE_PATTERN = re.compile(r'''
+      ^                   # Start of string
+      (                   # Group 1: The numeric value
+          \d+             #   One or more digits (integer part)
+          (?:\.\d+)?      #   Optional: decimal point followed by digits
+      )                   #   Examples: "10", "0.5", "100.25"
+      (                   # Group 2: Optional unit suffix
+          hz              #   "hz" - hertz
+          | khz           #   "khz" - kilohertz
+          | k             #   "k" - shorthand for kilohertz
+      )?                  #   Suffix is optional (bare number = Hz)
+      $                   # End of string
+  ''', re.VERBOSE | re.IGNORECASE)
+
+
+def _parse_sampling_rate(rate_str: str) -> int:
+    """Parse sampling rate string to microseconds."""
+    rate_str = rate_str.strip().lower()
+
+    match = _RATE_PATTERN.match(rate_str)
+    if not match:
+        raise argparse.ArgumentTypeError(
+            f"Invalid sampling rate format: {rate_str}. "
+            "Expected: number followed by optional suffix (hz, khz, k) with no 
spaces (e.g., 10khz)"
+        )
+
+    number_part = match.group(1)
+    suffix = match.group(2) or ''
+
+    # Determine multiplier based on suffix
+    suffix_map = {
+        'hz': 1,
+        'khz': 1000,
+        'k': 1000,
+    }
+    multiplier = suffix_map.get(suffix, 1)
+    hz = float(number_part) * multiplier
+    if hz <= 0:
+        raise argparse.ArgumentTypeError(f"Sampling rate must be positive: 
{rate_str}")
+
+    interval_usec = int(MICROSECONDS_PER_SECOND / hz)
+    if interval_usec < 1:
+        raise argparse.ArgumentTypeError(f"Sampling rate too high: {rate_str}")
+
+    return interval_usec
+
+
 def _add_sampling_options(parser):
     """Add sampling configuration options to a parser."""
     sampling_group = parser.add_argument_group("Sampling configuration")
     sampling_group.add_argument(
-        "-i",
-        "--interval",
-        type=int,
-        default=100,
-        metavar="MICROSECONDS",
-        help="sampling interval",
+        "-r",
+        "--sampling-rate",
+        type=_parse_sampling_rate,
+        default="1khz",
+        metavar="RATE",
+        dest="sample_interval_usec",
+        help="sampling rate (e.g., 10000, 10khz, 10k)",
     )
     sampling_group.add_argument(
         "-d",
@@ -487,14 +538,13 @@ def _sort_to_mode(sort_choice):
     }
     return sort_map.get(sort_choice, SORT_MODE_NSAMPLES)
 
-
-def _create_collector(format_type, interval, skip_idle, opcodes=False,
+def _create_collector(format_type, sample_interval_usec, skip_idle, 
opcodes=False,
                       output_file=None, compression='auto'):
     """Create the appropriate collector based on format type.
 
     Args:
         format_type: The output format ('pstats', 'collapsed', 'flamegraph', 
'gecko', 'heatmap', 'binary')
-        interval: Sampling interval in microseconds
+        sample_interval_usec: Sampling interval in microseconds
         skip_idle: Whether to skip idle samples
         opcodes: Whether to collect opcode information (only used by gecko 
format
                  for creating interval markers in Firefox Profiler)
@@ -519,9 +569,9 @@ def _create_collector(format_type, interval, skip_idle, 
opcodes=False,
     # and is the only format that uses opcodes for interval markers
     if format_type == "gecko":
         skip_idle = False
-        return collector_class(interval, skip_idle=skip_idle, opcodes=opcodes)
+        return collector_class(sample_interval_usec, skip_idle=skip_idle, 
opcodes=opcodes)
 
-    return collector_class(interval, skip_idle=skip_idle)
+    return collector_class(sample_interval_usec, skip_idle=skip_idle)
 
 
 def _generate_output_filename(format_type, pid):
@@ -725,8 +775,8 @@ def _main():
   # Generate flamegraph from a script
   `python -m profiling.sampling run --flamegraph -o output.html script.py`
 
-  # Profile with custom interval and duration
-  `python -m profiling.sampling run -i 50 -d 30 script.py`
+  # Profile with custom rate and duration
+  `python -m profiling.sampling run -r 5khz -d 30 script.py`
 
   # Save collapsed stacks to file
   `python -m profiling.sampling run --collapsed -o stacks.txt script.py`
@@ -860,7 +910,7 @@ def _handle_attach(args):
 
     # Create the appropriate collector
     collector = _create_collector(
-        args.format, args.interval, skip_idle, args.opcodes,
+        args.format, args.sample_interval_usec, skip_idle, args.opcodes,
         output_file=output_file,
         compression=getattr(args, 'compression', 'auto')
     )
@@ -938,7 +988,7 @@ def _handle_run(args):
 
     # Create the appropriate collector
     collector = _create_collector(
-        args.format, args.interval, skip_idle, args.opcodes,
+        args.format, args.sample_interval_usec, skip_idle, args.opcodes,
         output_file=output_file,
         compression=getattr(args, 'compression', 'auto')
     )
@@ -965,7 +1015,7 @@ def _handle_run(args):
             if process.poll() is None:
                 process.terminate()
                 try:
-                    process.wait(timeout=_PROCESS_KILL_TIMEOUT)
+                    process.wait(timeout=_PROCESS_KILL_TIMEOUT_SEC)
                 except subprocess.TimeoutExpired:
                     process.kill()
                     process.wait()
@@ -980,7 +1030,7 @@ def _handle_live_attach(args, pid):
 
     # Create live collector with default settings
     collector = LiveStatsCollector(
-        args.interval,
+        args.sample_interval_usec,
         skip_idle=skip_idle,
         sort_by="tottime",  # Default initial sort
         limit=20,  # Default limit
@@ -1027,7 +1077,7 @@ def _handle_live_run(args):
 
     # Create live collector with default settings
     collector = LiveStatsCollector(
-        args.interval,
+        args.sample_interval_usec,
         skip_idle=skip_idle,
         sort_by="tottime",  # Default initial sort
         limit=20,  # Default limit
diff --git a/Lib/profiling/sampling/constants.py 
b/Lib/profiling/sampling/constants.py
index 34b85ba4b3c61d..366cbb38365c9f 100644
--- a/Lib/profiling/sampling/constants.py
+++ b/Lib/profiling/sampling/constants.py
@@ -1,5 +1,9 @@
 """Constants for the sampling profiler."""
 
+# Time unit conversion constants
+MICROSECONDS_PER_SECOND = 1_000_000
+MILLISECONDS_PER_SECOND = 1_000
+
 # Profiling mode constants
 PROFILING_MODE_WALL = 0
 PROFILING_MODE_CPU = 1
diff --git a/Lib/profiling/sampling/live_collector/__init__.py 
b/Lib/profiling/sampling/live_collector/__init__.py
index 175e4610d232c5..59d50955e52959 100644
--- a/Lib/profiling/sampling/live_collector/__init__.py
+++ b/Lib/profiling/sampling/live_collector/__init__.py
@@ -114,7 +114,7 @@
 from .constants import (
     MICROSECONDS_PER_SECOND,
     DISPLAY_UPDATE_HZ,
-    DISPLAY_UPDATE_INTERVAL,
+    DISPLAY_UPDATE_INTERVAL_SEC,
     MIN_TERMINAL_WIDTH,
     MIN_TERMINAL_HEIGHT,
     WIDTH_THRESHOLD_SAMPLE_PCT,
@@ -165,7 +165,7 @@
     # Constants
     "MICROSECONDS_PER_SECOND",
     "DISPLAY_UPDATE_HZ",
-    "DISPLAY_UPDATE_INTERVAL",
+    "DISPLAY_UPDATE_INTERVAL_SEC",
     "MIN_TERMINAL_WIDTH",
     "MIN_TERMINAL_HEIGHT",
     "WIDTH_THRESHOLD_SAMPLE_PCT",
diff --git a/Lib/profiling/sampling/live_collector/collector.py 
b/Lib/profiling/sampling/live_collector/collector.py
index dcb9fcabe32779..cdf95a77eeccd8 100644
--- a/Lib/profiling/sampling/live_collector/collector.py
+++ b/Lib/profiling/sampling/live_collector/collector.py
@@ -24,7 +24,7 @@
 )
 from .constants import (
     MICROSECONDS_PER_SECOND,
-    DISPLAY_UPDATE_INTERVAL,
+    DISPLAY_UPDATE_INTERVAL_SEC,
     MIN_TERMINAL_WIDTH,
     MIN_TERMINAL_HEIGHT,
     HEADER_LINES,
@@ -157,7 +157,7 @@ def __init__(
         self.max_sample_rate = 0  # Track maximum sample rate seen
         self.successful_samples = 0  # Track samples that captured frames
         self.failed_samples = 0  # Track samples that failed to capture frames
-        self.display_update_interval = DISPLAY_UPDATE_INTERVAL  # Instance 
variable for display refresh rate
+        self.display_update_interval_sec = DISPLAY_UPDATE_INTERVAL_SEC  # 
Instance variable for display refresh rate
 
         # Thread status statistics (bit flags)
         self.thread_status_counts = {
@@ -410,7 +410,7 @@ def collect(self, stack_frames, timestamp_us=None):
             if (
                 self._last_display_update is None
                 or (current_time - self._last_display_update)
-                >= self.display_update_interval
+                >= self.display_update_interval_sec
             ):
                 self._update_display()
                 self._last_display_update = current_time
@@ -987,14 +987,14 @@ def _handle_input(self):
 
         elif ch == ord("+") or ch == ord("="):
             # Decrease update interval (faster refresh)
-            self.display_update_interval = max(
-                0.05, self.display_update_interval - 0.05
+            self.display_update_interval_sec = max(
+                0.05, self.display_update_interval_sec - 0.05
             )  # Min 20Hz
 
         elif ch == ord("-") or ch == ord("_"):
             # Increase update interval (slower refresh)
-            self.display_update_interval = min(
-                1.0, self.display_update_interval + 0.05
+            self.display_update_interval_sec = min(
+                1.0, self.display_update_interval_sec + 0.05
             )  # Max 1Hz
 
         elif ch == ord("c") or ch == ord("C"):
diff --git a/Lib/profiling/sampling/live_collector/constants.py 
b/Lib/profiling/sampling/live_collector/constants.py
index 8462c0de3fd680..4f4575f7b7aae2 100644
--- a/Lib/profiling/sampling/live_collector/constants.py
+++ b/Lib/profiling/sampling/live_collector/constants.py
@@ -5,7 +5,7 @@
 
 # Display update constants
 DISPLAY_UPDATE_HZ = 10
-DISPLAY_UPDATE_INTERVAL = 1.0 / DISPLAY_UPDATE_HZ  # 0.1 seconds
+DISPLAY_UPDATE_INTERVAL_SEC = 1.0 / DISPLAY_UPDATE_HZ  # 0.1 seconds
 
 # Terminal size constraints
 MIN_TERMINAL_WIDTH = 60
diff --git a/Lib/profiling/sampling/live_collector/widgets.py 
b/Lib/profiling/sampling/live_collector/widgets.py
index 314f3796a093ad..cf04f3aa3254ef 100644
--- a/Lib/profiling/sampling/live_collector/widgets.py
+++ b/Lib/profiling/sampling/live_collector/widgets.py
@@ -13,7 +13,7 @@
     WIDTH_THRESHOLD_CUMUL_PCT,
     WIDTH_THRESHOLD_CUMTIME,
     MICROSECONDS_PER_SECOND,
-    DISPLAY_UPDATE_INTERVAL,
+    DISPLAY_UPDATE_INTERVAL_SEC,
     MIN_BAR_WIDTH,
     MAX_SAMPLE_RATE_BAR_WIDTH,
     MAX_EFFICIENCY_BAR_WIDTH,
@@ -181,7 +181,7 @@ def draw_header_info(self, line, width, elapsed):
 
         # Calculate display refresh rate
         refresh_hz = (
-            1.0 / self.collector.display_update_interval if 
self.collector.display_update_interval > 0 else 0
+            1.0 / self.collector.display_update_interval_sec if 
self.collector.display_update_interval_sec > 0 else 0
         )
 
         # Get current view mode and thread display
@@ -235,8 +235,8 @@ def draw_header_info(self, line, width, elapsed):
 
     def format_rate_with_units(self, rate_hz):
         """Format a rate in Hz with appropriate units (Hz, KHz, MHz)."""
-        if rate_hz >= 1_000_000:
-            return f"{rate_hz / 1_000_000:.1f}MHz"
+        if rate_hz >= MICROSECONDS_PER_SECOND:
+            return f"{rate_hz / MICROSECONDS_PER_SECOND:.1f}MHz"
         elif rate_hz >= 1_000:
             return f"{rate_hz / 1_000:.1f}KHz"
         else:
diff --git a/Lib/profiling/sampling/pstats_collector.py 
b/Lib/profiling/sampling/pstats_collector.py
index 1b2fe6a77278ee..e0dc9ab6bb7edb 100644
--- a/Lib/profiling/sampling/pstats_collector.py
+++ b/Lib/profiling/sampling/pstats_collector.py
@@ -3,6 +3,7 @@
 
 from _colorize import ANSIColors
 from .collector import Collector, extract_lineno
+from .constants import MICROSECONDS_PER_SECOND
 
 
 class PstatsCollector(Collector):
@@ -68,7 +69,7 @@ def _dump_stats(self, file):
 
     # Needed for compatibility with pstats.Stats
     def create_stats(self):
-        sample_interval_sec = self.sample_interval_usec / 1_000_000
+        sample_interval_sec = self.sample_interval_usec / 
MICROSECONDS_PER_SECOND
         callers = {}
         for fname, call_counts in self.result.items():
             total = call_counts["direct_calls"] * sample_interval_sec
@@ -263,7 +264,7 @@ def _determine_best_unit(max_value):
         elif max_value >= 0.001:
             return "ms", 1000.0
         else:
-            return "μs", 1000000.0
+            return "μs", float(MICROSECONDS_PER_SECOND)
 
     def _print_summary(self, stats_list, total_samples):
         """Print summary of interesting functions."""
diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py 
b/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py
index ef9ea64b67af61..bcd4de7f5d7ebe 100644
--- a/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py
+++ b/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py
@@ -219,8 +219,8 @@ def worker(x):
                     "run",
                     "-d",
                     "5",
-                    "-i",
-                    "100000",
+                    "-r",
+                    "10",
                     script,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE,
diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_children.py 
b/Lib/test/test_profiling/test_sampling_profiler/test_children.py
index 4007b3e8d7a41f..b7dc878a238f8d 100644
--- a/Lib/test/test_profiling/test_sampling_profiler/test_children.py
+++ b/Lib/test/test_profiling/test_sampling_profiler/test_children.py
@@ -279,11 +279,11 @@ def test_monitor_creation(self):
 
         monitor = ChildProcessMonitor(
             pid=os.getpid(),
-            cli_args=["-i", "100", "-d", "5"],
+            cli_args=["-r", "10khz", "-d", "5"],
             output_pattern="test_{pid}.pstats",
         )
         self.assertEqual(monitor.parent_pid, os.getpid())
-        self.assertEqual(monitor.cli_args, ["-i", "100", "-d", "5"])
+        self.assertEqual(monitor.cli_args, ["-r", "10khz", "-d", "5"])
         self.assertEqual(monitor.output_pattern, "test_{pid}.pstats")
 
     def test_monitor_lifecycle(self):
@@ -386,7 +386,7 @@ def test_build_child_profiler_args(self):
         from profiling.sampling.cli import _build_child_profiler_args
 
         args = argparse.Namespace(
-            interval=200,
+            sample_interval_usec=200,
             duration=15,
             all_threads=True,
             realtime_stats=False,
@@ -420,7 +420,7 @@ def assert_flag_value_pair(flag, value):
                 f"'{child_args[flag_index + 1]}' in args: {child_args}",
             )
 
-        assert_flag_value_pair("-i", 200)
+        assert_flag_value_pair("-r", 5000)
         assert_flag_value_pair("-d", 15)
         assert_flag_value_pair("--mode", "cpu")
 
@@ -444,7 +444,7 @@ def test_build_child_profiler_args_no_gc(self):
         from profiling.sampling.cli import _build_child_profiler_args
 
         args = argparse.Namespace(
-            interval=100,
+            sample_interval_usec=100,
             duration=5,
             all_threads=False,
             realtime_stats=False,
@@ -510,7 +510,7 @@ def test_setup_child_monitor(self):
         from profiling.sampling.cli import _setup_child_monitor
 
         args = argparse.Namespace(
-            interval=100,
+            sample_interval_usec=100,
             duration=5,
             all_threads=False,
             realtime_stats=False,
@@ -690,7 +690,7 @@ def test_monitor_respects_max_limit(self):
         # Create a monitor
         monitor = ChildProcessMonitor(
             pid=os.getpid(),
-            cli_args=["-i", "100", "-d", "5"],
+            cli_args=["-r", "10khz", "-d", "5"],
             output_pattern="test_{pid}.pstats",
         )
 
@@ -927,8 +927,8 @@ def 
test_subprocesses_flag_spawns_child_and_creates_output(self):
                     "--subprocesses",
                     "-d",
                     "3",
-                    "-i",
-                    "10000",
+                    "-r",
+                    "100",
                     "-o",
                     output_file,
                     script_file,
@@ -989,8 +989,8 @@ def test_subprocesses_flag_with_flamegraph_output(self):
                     "--subprocesses",
                     "-d",
                     "2",
-                    "-i",
-                    "10000",
+                    "-r",
+                    "100",
                     "--flamegraph",
                     "-o",
                     output_file,
@@ -1043,8 +1043,8 @@ def test_subprocesses_flag_no_crash_on_quick_child(self):
                     "--subprocesses",
                     "-d",
                     "2",
-                    "-i",
-                    "10000",
+                    "-r",
+                    "100",
                     "-o",
                     output_file,
                     script_file,
diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py 
b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py
index 9b2b16d6e1965b..fb4816a0b6085a 100644
--- a/Lib/test/test_profiling/test_sampling_profiler/test_cli.py
+++ b/Lib/test/test_profiling/test_sampling_profiler/test_cli.py
@@ -232,7 +232,7 @@ def test_cli_module_with_profiler_options(self):
         test_args = [
             "profiling.sampling.cli",
             "run",
-            "-i",
+            "-r",
             "1000",
             "-d",
             "30",
@@ -265,8 +265,8 @@ def test_cli_script_with_profiler_options(self):
         test_args = [
             "profiling.sampling.cli",
             "run",
-            "-i",
-            "2000",
+            "-r",
+            "500",
             "-d",
             "60",
             "--collapsed",
diff --git 
a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py
 
b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py
index a5870366552854..38f1d03e4939f1 100644
--- 
a/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py
+++ 
b/Lib/test/test_profiling/test_sampling_profiler/test_live_collector_interaction.py
@@ -35,7 +35,7 @@ def setUp(self):
         )
         self.collector.start_time = time.perf_counter()
         # Set a consistent display update interval for tests
-        self.collector.display_update_interval = 0.1
+        self.collector.display_update_interval_sec = 0.1
 
     def tearDown(self):
         """Clean up after test."""
@@ -110,45 +110,45 @@ def test_reset_stats(self):
 
     def test_increase_refresh_rate(self):
         """Test increasing refresh rate (faster updates)."""
-        initial_interval = self.collector.display_update_interval
+        initial_interval = self.collector.display_update_interval_sec
 
         # Simulate '+' key press (faster = smaller interval)
         self.display.simulate_input(ord("+"))
         self.collector._handle_input()
 
-        self.assertLess(self.collector.display_update_interval, 
initial_interval)
+        self.assertLess(self.collector.display_update_interval_sec, 
initial_interval)
 
     def test_decrease_refresh_rate(self):
         """Test decreasing refresh rate (slower updates)."""
-        initial_interval = self.collector.display_update_interval
+        initial_interval = self.collector.display_update_interval_sec
 
         # Simulate '-' key press (slower = larger interval)
         self.display.simulate_input(ord("-"))
         self.collector._handle_input()
 
-        self.assertGreater(self.collector.display_update_interval, 
initial_interval)
+        self.assertGreater(self.collector.display_update_interval_sec, 
initial_interval)
 
     def test_refresh_rate_minimum(self):
         """Test that refresh rate has a minimum (max speed)."""
-        self.collector.display_update_interval = 0.05  # Set to minimum
+        self.collector.display_update_interval_sec = 0.05  # Set to minimum
 
         # Try to go faster
         self.display.simulate_input(ord("+"))
         self.collector._handle_input()
 
         # Should stay at minimum
-        self.assertEqual(self.collector.display_update_interval, 0.05)
+        self.assertEqual(self.collector.display_update_interval_sec, 0.05)
 
     def test_refresh_rate_maximum(self):
         """Test that refresh rate has a maximum (min speed)."""
-        self.collector.display_update_interval = 1.0  # Set to maximum
+        self.collector.display_update_interval_sec = 1.0  # Set to maximum
 
         # Try to go slower
         self.display.simulate_input(ord("-"))
         self.collector._handle_input()
 
         # Should stay at maximum
-        self.assertEqual(self.collector.display_update_interval, 1.0)
+        self.assertEqual(self.collector.display_update_interval_sec, 1.0)
 
     def test_help_toggle(self):
         """Test help screen toggle."""
@@ -289,23 +289,23 @@ def test_filter_clear_uppercase(self):
 
     def test_increase_refresh_rate_with_equals(self):
         """Test increasing refresh rate with '=' key."""
-        initial_interval = self.collector.display_update_interval
+        initial_interval = self.collector.display_update_interval_sec
 
         # Simulate '=' key press (alternative to '+')
         self.display.simulate_input(ord("="))
         self.collector._handle_input()
 
-        self.assertLess(self.collector.display_update_interval, 
initial_interval)
+        self.assertLess(self.collector.display_update_interval_sec, 
initial_interval)
 
     def test_decrease_refresh_rate_with_underscore(self):
         """Test decreasing refresh rate with '_' key."""
-        initial_interval = self.collector.display_update_interval
+        initial_interval = self.collector.display_update_interval_sec
 
         # Simulate '_' key press (alternative to '-')
         self.display.simulate_input(ord("_"))
         self.collector._handle_input()
 
-        self.assertGreater(self.collector.display_update_interval, 
initial_interval)
+        self.assertGreater(self.collector.display_update_interval_sec, 
initial_interval)
 
     def test_finished_state_displays_banner(self):
         """Test that finished state shows prominent banner."""
diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_modes.py 
b/Lib/test/test_profiling/test_sampling_profiler/test_modes.py
index 247416389daa07..877237866b1e65 100644
--- a/Lib/test/test_profiling/test_sampling_profiler/test_modes.py
+++ b/Lib/test/test_profiling/test_sampling_profiler/test_modes.py
@@ -306,8 +306,8 @@ def test_gil_mode_cli_argument_parsing(self):
             "12345",
             "--mode",
             "gil",
-            "-i",
-            "500",
+            "-r",
+            "2000",
             "-d",
             "5",
         ]
@@ -488,8 +488,8 @@ def test_exception_mode_cli_argument_parsing(self):
             "12345",
             "--mode",
             "exception",
-            "-i",
-            "500",
+            "-r",
+            "2000",
             "-d",
             "5",
         ]

_______________________________________________
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