Skip to content

perf: Query distro.version sources lazily#379

Open
ichard26 wants to merge 1 commit into
python-distro:masterfrom
ichard26:optimize-version
Open

perf: Query distro.version sources lazily#379
ichard26 wants to merge 1 commit into
python-distro:masterfrom
ichard26:optimize-version

Conversation

@ichard26

@ichard26 ichard26 commented Jun 10, 2026

Copy link
Copy Markdown

Hey, I first wanted to say thanks for maintaining distro. From the pip team, we appreciate it!


When /etc/os-release provides sufficiently high-quality version information directly, there is no need to call lsb_release in a subprocess or query any other version.

This speeds up distro.version() massively when lsb_release is slow to execute, like on Ubuntu 26.04 LTS where it can easily take north of 15ms.

For context, pip uses distro.version() to populate its user-agent header so we'd like this function to be as fast as reasonably possible.

For benchmarking, you can use this which is equivalent to what pip does:

import distro
import time

def run():
    t0 = time.perf_counter()
    linux_distribution = distro.name(), distro.version(), distro.codename()
    t1 = time.perf_counter()

    print(f"elapsed: {(t1 - t0)*1000:.2f}ms")

run()

Under CPython 3.15's new sampling profiler on Ubuntu 26.04 LTS:

~/dev/oss/distro ❯ python -m profiling.sampling run -r 30khz test.py
elapsed: 16.21ms
Captured 1,028 samples in 0.03 seconds
Sample rate: 30,302.98 samples/sec
Error rate: 24.61
Profile Stats:
       nsamples   sample%  tottime (ms)    cumul%  cumtime (ms)  filename:lineno(function)
        429/429      55.5        14.157      55.5        14.157  subprocess.py:1376(Popen.communicate)
        157/291      20.3         5.181      37.6         9.603  <frozen importlib._bootstrap>:549(_call_with_frames_removed)
          45/45       5.8         1.485       5.8         1.485  <frozen importlib._bootstrap_external>:500(_compile_bytecode)
          24/24       3.1         0.792       3.1         0.792  subprocess.py:2080(Popen._execute_child)
            8/8       1.0         0.264       1.0         0.264  <frozen genericpath>:40(isfile)
            5/5       0.6         0.165       0.6         0.165  <frozen importlib._bootstrap_external>:213(_write_atomic)
            5/5       0.6         0.165       0.6         0.165  _parser.py:450(_uniq)
            4/4       0.5         0.132       0.5         0.132  <frozen importlib._bootstrap_external>:923(FileLoader.get_data)
            3/3       0.4         0.099       0.4         0.099  <frozen importlib._bootstrap_external>:517(_code_to_timestamp_pyc)
            3/3       0.4         0.099       0.4         0.099  <frozen importlib._bootstrap_external>:152(_path_stat)
            3/3       0.4         0.099       0.4         0.099  __init__.py:447(namedtuple)
            3/3       0.4         0.099       0.4         0.099  distro.py:1351(LinuxDistribution._distro_release_info)
            2/2       0.3         0.066       0.3         0.066  <frozen importlib._bootstrap_external>:211(_write_atomic)
            2/2       0.3         0.066       0.3         0.066  argparse.py:1020(<module>)
            2/2       0.3         0.066       0.3         0.066  __init__.py:515(namedtuple)

Legend:
  nsamples: Direct/Cumulative samples (direct executing / on call stack)
  sample%: Percentage of total samples this function was directly executing
  tottime: Estimated total time spent directly in this function
  cumul%: Percentage of total samples when this function was on the call stack
  cumtime: Estimated cumulative time (including time in called functions)
  filename:lineno(function): Function location and name

When /etc/os-release provides sufficiently high-quality version
information directly, there is no need to call lsb_release in a
subprocess or query any other version.

This speeds up distro.version() massively when lsb_release is slow to
execute, like on Ubuntu 26.04 LTS where it can easily take north of
15ms.

For context, pip uses distro.version() to populate its user-agent header
so we'd like this function to be as fast as reasonably possible.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants