Skip to content

perf: Query distro.version sources lazily#379

Merged
nir0s merged 1 commit into
python-distro:masterfrom
ichard26:optimize-version
Jun 29, 2026
Merged

perf: Query distro.version sources lazily#379
nir0s merged 1 commit into
python-distro:masterfrom
ichard26:optimize-version

Conversation

@ichard26

@ichard26 ichard26 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

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.

@HorlogeSkynet HorlogeSkynet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @ichard26, and thanks for your patch. I agree it's a great improvement when best=False.

@nir0s

nir0s commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

@HorlogeSkynet, did you not merge on purpose?

@HorlogeSkynet

Copy link
Copy Markdown
Member

@HorlogeSkynet, did you not merge on purpose?

Yes, just in case one wanted to express a different opinion on the matter. We can merge if you approve too !

@nir0s nir0s merged commit 7f6dae9 into python-distro:master Jun 29, 2026
10 checks passed
@ichard26 ichard26 deleted the optimize-version branch June 30, 2026 20:13
@ichard26

ichard26 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Thanks / merci beaucoup ! I'm looking forward to a release.

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.

3 participants