Gentoo Archives: gentoo-portage-dev

From: Chun-Yu Shei <cshei@××××××.com>
To: gentoo-portage-dev@l.g.o
Cc: Chun-Yu Shei <cshei@××××××.com>
Subject: [gentoo-portage-dev] [PATCH] Add caching to use_reduce, vercmp, and catpkgsplit
Date: Mon, 13 Jul 2020 06:30:28
Message-Id: 20200713063020.820029-2-cshei@google.com
In Reply to: Re: [gentoo-portage-dev] [PATCH] Add caching to use_reduce, by Chun-Yu Shei
1 Each of these functions is called repeatedly with the same arguments
2 many times. Cache sizes were selected to minimize memory use increase,
3 while still providing about the same speedup compared to a cache with
4 unbounded size. "emerge -uDvpU --with-bdeps=y @world" runtime decreases
5 from 44.32s -> 29.94s -- a 48% speedup, while the maximum value of the
6 RES column in htop increases from 280 MB -> 290 MB.
7
8 "emerge -ep @world" time slightly decreases from 18.77s -> 17.93, while
9 max observed RES value actually decreases from 228 MB -> 214 MB (similar
10 values observed across a few before/after runs).
11 ---
12 lib/portage/dep/__init__.py | 107 +++++++++++++++++++++---------------
13 lib/portage/versions.py | 3 +
14 2 files changed, 67 insertions(+), 43 deletions(-)
15
16 diff --git a/lib/portage/dep/__init__.py b/lib/portage/dep/__init__.py
17 index 72988357a..314338f7c 100644
18 --- a/lib/portage/dep/__init__.py
19 +++ b/lib/portage/dep/__init__.py
20 @@ -17,6 +17,7 @@ __all__ = [
21
22 import re, sys
23 import warnings
24 +from functools import lru_cache
25
26 import portage
27 portage.proxy.lazyimport.lazyimport(globals(),
28 @@ -404,49 +405,10 @@ def paren_enclose(mylist, unevaluated_atom=False, opconvert=False):
29 mystrparts.append(x)
30 return " ".join(mystrparts)
31
32 -def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), is_src_uri=False, \
33 - eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False,
34 - subset=None):
35 - """
36 - Takes a dep string and reduces the use? conditionals out, leaving an array
37 - with subarrays. All redundant brackets are removed.
38 -
39 - @param depstr: depstring
40 - @type depstr: String
41 - @param uselist: Sequence of use enabled flags
42 - @type uselist: Sequence
43 - @param masklist: Sequence of masked flags (always treated as disabled)
44 - @type masklist: Sequence
45 - @param matchall: Treat all conditionals as active. Used by repoman.
46 - @type matchall: Bool
47 - @param excludeall: Sequence of flags for which negated conditionals are always treated as inactive.
48 - @type excludeall: Sequence
49 - @param is_src_uri: Indicates if depstr represents a SRC_URI
50 - @type is_src_uri: Bool
51 - @param eapi: Indicates the EAPI the dep string has to comply to
52 - @type eapi: String
53 - @param opconvert: Put every operator as first element into it's argument list
54 - @type opconvert: Bool
55 - @param flat: Create a flat list of all tokens
56 - @type flat: Bool
57 - @param is_valid_flag: Function that decides if a given use flag might be used in use conditionals
58 - @type is_valid_flag: Function
59 - @param token_class: Convert all non operator tokens into this class
60 - @type token_class: Class
61 - @param matchnone: Treat all conditionals as inactive. Used by digestgen().
62 - @type matchnone: Bool
63 - @param subset: Select a subset of dependencies conditional on the given flags
64 - @type subset: Sequence
65 - @rtype: List
66 - @return: The use reduced depend array
67 - """
68 - if isinstance(depstr, list):
69 - if portage._internal_caller:
70 - warnings.warn(_("Passing paren_reduced dep arrays to %s is deprecated. " + \
71 - "Pass the original dep string instead.") % \
72 - ('portage.dep.use_reduce',), DeprecationWarning, stacklevel=2)
73 - depstr = paren_enclose(depstr)
74 -
75 +@lru_cache(1024)
76 +def _use_reduce_cached(depstr, uselist, masklist, matchall, excludeall, \
77 + is_src_uri, eapi, opconvert, flat, is_valid_flag, token_class, \
78 + matchnone,subset):
79 if opconvert and flat:
80 raise ValueError("portage.dep.use_reduce: 'opconvert' and 'flat' are mutually exclusive")
81
82 @@ -769,6 +731,65 @@ def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), i
83
84 return stack[0]
85
86 +def use_reduce(depstr, uselist=(), masklist=(), matchall=False, excludeall=(), is_src_uri=False, \
87 + eapi=None, opconvert=False, flat=False, is_valid_flag=None, token_class=None, matchnone=False,
88 + subset=None):
89 + """
90 + Takes a dep string and reduces the use? conditionals out, leaving an array
91 + with subarrays. All redundant brackets are removed.
92 +
93 + @param depstr: depstring
94 + @type depstr: String
95 + @param uselist: Sequence of use enabled flags
96 + @type uselist: Sequence
97 + @param masklist: Sequence of masked flags (always treated as disabled)
98 + @type masklist: Sequence
99 + @param matchall: Treat all conditionals as active. Used by repoman.
100 + @type matchall: Bool
101 + @param excludeall: Sequence of flags for which negated conditionals are always treated as inactive.
102 + @type excludeall: Sequence
103 + @param is_src_uri: Indicates if depstr represents a SRC_URI
104 + @type is_src_uri: Bool
105 + @param eapi: Indicates the EAPI the dep string has to comply to
106 + @type eapi: String
107 + @param opconvert: Put every operator as first element into it's argument list
108 + @type opconvert: Bool
109 + @param flat: Create a flat list of all tokens
110 + @type flat: Bool
111 + @param is_valid_flag: Function that decides if a given use flag might be used in use conditionals
112 + @type is_valid_flag: Function
113 + @param token_class: Convert all non operator tokens into this class
114 + @type token_class: Class
115 + @param matchnone: Treat all conditionals as inactive. Used by digestgen().
116 + @type matchnone: Bool
117 + @param subset: Select a subset of dependencies conditional on the given flags
118 + @type subset: Sequence
119 + @rtype: List
120 + @return: The use reduced depend array
121 + """
122 + if isinstance(depstr, list):
123 + if portage._internal_caller:
124 + warnings.warn(_("Passing paren_reduced dep arrays to %s is deprecated. " + \
125 + "Pass the original dep string instead.") % \
126 + ('portage.dep.use_reduce',), DeprecationWarning, stacklevel=2)
127 + depstr = paren_enclose(depstr)
128 +
129 + if uselist is not None:
130 + uselist = frozenset(uselist)
131 + if masklist is not None:
132 + masklist = frozenset(masklist)
133 + if excludeall is not None:
134 + excludeall = frozenset(excludeall)
135 + if subset is not None:
136 + subset = frozenset(subset)
137 +
138 + result = _use_reduce_cached(depstr, uselist, masklist, matchall, \
139 + excludeall, is_src_uri, eapi, opconvert, flat, is_valid_flag, \
140 + token_class, matchnone, subset)
141 +
142 + # The list returned by this function may be modified, so return a copy.
143 + return result[:]
144 +
145 def dep_opconvert(deplist):
146 """
147 Iterate recursively through a list of deps, if the
148 diff --git a/lib/portage/versions.py b/lib/portage/versions.py
149 index 0c21373cc..100c8b84d 100644
150 --- a/lib/portage/versions.py
151 +++ b/lib/portage/versions.py
152 @@ -13,6 +13,7 @@ __all__ = [
153 import re
154 import sys
155 import warnings
156 +from functools import lru_cache
157
158 if sys.hexversion < 0x3000000:
159 _unicode = unicode
160 @@ -116,6 +117,7 @@ def ververify(myver, silent=1):
161 print(_("!!! syntax error in version: %s") % myver)
162 return False
163
164 +@lru_cache(1024)
165 def vercmp(ver1, ver2, silent=1):
166 """
167 Compare two versions
168 @@ -313,6 +315,7 @@ def _pkgsplit(mypkg, eapi=None):
169 _cat_re = re.compile('^%s$' % _cat, re.UNICODE)
170 _missing_cat = 'null'
171
172 +@lru_cache(10240)
173 def catpkgsplit(mydata, silent=1, eapi=None):
174 """
175 Takes a Category/Package-Version-Rev and returns a list of each.
176 --
177 2.27.0.389.gc38d7665816-goog

Replies