Skip to content

Commit

Permalink
Show @lru_cache stats if PORTAGE_SHOW_LRU_CACHE_INFO env var is set
Browse files Browse the repository at this point in the history
This introduces the PORTAGE_SHOW_LRU_CACHE_INFO environment variable.

Setting the PORTAGE_SHOW_LRU_CACHE_INFO environment variable allows to
analyze the effectiveness and potential bottlenecks of the @lru_cache
annotation used by portage. The cache information will be printed
after dependency calculation and after emerge "finished".

Example output:
Portage @lru_cache information
use_reduce_cached: hit ratio: 71.25% (total: 48575, hits: 34611, misses: 13964) util: 100.00% (1024 / 1024)
encoded_length: hit ratio: 0.00% (total: 0, hits: 0, misses: 0) util: 0.00% (1024 / 0)
vercmp: hit ratio: 69.50% (total: 1777, hits: 1235, misses: 542) util: 52.93% (1024 / 542)
catpkgsplit: hit ratio: 66.90% (total: 191511, hits: 128129, misses: 63382) util: 100.00% (10240 / 10240)
get_eapi_attrs: hit ratio: 100.00% (total: 267206, hits: 267200, misses: 6) util: 18.75% (32 / 6)

Signed-off-by: Florian Schmaus <[email protected]>
  • Loading branch information
Flowdalic committed Feb 7, 2025
1 parent c75b61b commit ee61a15
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
2 changes: 2 additions & 0 deletions lib/_emerge/depgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
from portage.util.digraph import digraph
from portage.util.futures import asyncio
from portage.util._async.TaskScheduler import TaskScheduler
from portage.util.portage_lru_cache import show_lru_cache_info
from portage.versions import _pkg_str, catpkgsplit
from portage.binpkg import get_binpkg_format

Expand Down Expand Up @@ -11800,6 +11801,7 @@ def _spinner_stop(spinner, backtracked: int = -1, max_retries: int = -1):
portage.writemsg_stdout(
f"Dependency resolution took {darkgreen(time_fmt)} s{backtrack_info}.\n\n"
)
show_lru_cache_info()


def backtrack_depgraph(
Expand Down
3 changes: 3 additions & 0 deletions lib/_emerge/post_emerge.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from portage.output import colorize
from portage.util._dyn_libs.display_preserved_libs import display_preserved_libs
from portage.util._info_files import chk_updated_info_files
from portage.util.portage_lru_cache import show_lru_cache_info

from .chk_updated_cfg_files import chk_updated_cfg_files
from .emergelog import emergelog
Expand Down Expand Up @@ -169,3 +170,5 @@ def post_emerge(myaction, myopts, myfiles, target_root, trees, mtimedb, retval):

if "--quiet" not in myopts and myaction is None and "@world" in myfiles:
show_depclean_suggestion()

show_lru_cache_info()
12 changes: 7 additions & 5 deletions lib/portage/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,17 +323,19 @@ class EnvStats:
env_largest_size: int


@lru_cache(1024)
def _encoded_length(s):
return len(os.fsencode(s))


def calc_env_stats(env) -> EnvStats:
@lru_cache(1024)
def encoded_length(s):
return len(os.fsencode(s))

env_size = 0
env_largest_name = None
env_largest_size = 0
for env_name, env_value in env.items():
env_name_size = encoded_length(env_name)
env_value_size = encoded_length(env_value)
env_name_size = _encoded_length(env_name)
env_value_size = _encoded_length(env_value)
# Add two for '=' and the terminating null byte.
total_size = env_name_size + env_value_size + 2
if total_size > env_largest_size:
Expand Down
1 change: 1 addition & 0 deletions lib/portage/util/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ py.install_sources(
'mtimedb.py',
'netlink.py',
'path.py',
'portage_lru_cache.py',
'shelve.py',
'socks5.py',
'whirlpool.py',
Expand Down
42 changes: 42 additions & 0 deletions lib/portage/util/portage_lru_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

import os
import portage


def show_lru_cache_info():
if not os.environ.get("PORTAGE_SHOW_LRU_CACHE_INFO"):
return

portage_lru_caches = {
portage.dep._use_reduce_cached: "use_reduce_cached",
portage.process._encoded_length: "encoded_length",
portage.versions.vercmp: "vercmp",
portage.versions.catpkgsplit: "catpkgsplit",
portage.eapi._get_eapi_attrs: "get_eapi_attrs",
}

print("Portage @lru_cache information")
for method, name in portage_lru_caches.items():
cache_info = method.cache_info()

hits = cache_info.hits
misses = cache_info.misses
maxsize = cache_info.maxsize
currsize = cache_info.currsize

total = hits + misses
if total:
hitratio = hits / total
else:
hitratio = 0

if maxsize:
utilization = currsize / maxsize
else:
utilization = 0

pretty_cache_info = f"hit ratio: {hitratio:.2%} (total: {total}, hits: {hits}, misses: {misses}) util: {utilization:.2%} ({maxsize} / {currsize})"

print(f"{name}: {pretty_cache_info}")

0 comments on commit ee61a15

Please sign in to comment.