summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/codeparser.py
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2012-05-23 00:23:31 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2012-05-23 11:33:18 +0100
commitd7b818b51f3e6dded0c0885cdfed5a24cda3b428 (patch)
tree6cd18f70cb71682aad55a6079da32c25f60bcbf7 /bitbake/lib/bb/codeparser.py
parent644b30adfb8fb158a253712033f717aadf6f2c68 (diff)
downloadpoky-d7b818b51f3e6dded0c0885cdfed5a24cda3b428.tar.gz
bitbake: refactor out codeparser cache into a separate class
We want to be able to reuse most this functionality for the file checksum cache. (Bitbake rev: 0fe3cb1438d297f90dd0fc6b26362ecbff75c76d) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/codeparser.py')
-rw-r--r--bitbake/lib/bb/codeparser.py191
1 files changed, 57 insertions, 134 deletions
diff --git a/bitbake/lib/bb/codeparser.py b/bitbake/lib/bb/codeparser.py
index af2e19411c..d7d3f513d9 100644
--- a/bitbake/lib/bb/codeparser.py
+++ b/bitbake/lib/bb/codeparser.py
@@ -5,10 +5,10 @@ import os.path
5import bb.utils, bb.data 5import bb.utils, bb.data
6from itertools import chain 6from itertools import chain
7from pysh import pyshyacc, pyshlex, sherrors 7from pysh import pyshyacc, pyshlex, sherrors
8from bb.cache import MultiProcessCache
8 9
9 10
10logger = logging.getLogger('BitBake.CodeParser') 11logger = logging.getLogger('BitBake.CodeParser')
11PARSERCACHE_VERSION = 2
12 12
13try: 13try:
14 import cPickle as pickle 14 import cPickle as pickle
@@ -32,133 +32,56 @@ def check_indent(codestr):
32 32
33 return codestr 33 return codestr
34 34
35pythonparsecache = {}
36shellparsecache = {}
37pythonparsecacheextras = {}
38shellparsecacheextras = {}
39 35
40 36class CodeParserCache(MultiProcessCache):
41def parser_cachefile(d): 37 cache_file_name = "bb_codeparser.dat"
42 cachedir = (d.getVar("PERSISTENT_DIR", True) or 38 CACHE_VERSION = 2
43 d.getVar("CACHE", True)) 39
44 if cachedir in [None, '']: 40 def __init__(self):
45 return None 41 MultiProcessCache.__init__(self)
46 bb.utils.mkdirhier(cachedir) 42 self.pythoncache = self.cachedata[0]
47 cachefile = os.path.join(cachedir, "bb_codeparser.dat") 43 self.shellcache = self.cachedata[1]
48 logger.debug(1, "Using cache in '%s' for codeparser cache", cachefile) 44 self.pythoncacheextras = self.cachedata_extras[0]
49 return cachefile 45 self.shellcacheextras = self.cachedata_extras[1]
50 46
51def parser_cache_init(d): 47 def init_cache(self, d):
52 global pythonparsecache 48 MultiProcessCache.init_cache(self, d)
53 global shellparsecache 49
54 50 # cachedata gets re-assigned in the parent
55 cachefile = parser_cachefile(d) 51 self.pythoncache = self.cachedata[0]
56 if not cachefile: 52 self.shellcache = self.cachedata[1]
53
54 def compress_keys(self, data):
55 # When the dicts are originally created, python calls intern() on the set keys
56 # which significantly improves memory usage. Sadly the pickle/unpickle process
57 # doesn't call intern() on the keys and results in the same strings being duplicated
58 # in memory. This also means pickle will save the same string multiple times in
59 # the cache file. By interning the data here, the cache file shrinks dramatically
60 # meaning faster load times and the reloaded cache files also consume much less
61 # memory. This is worth any performance hit from this loops and the use of the
62 # intern() data storage.
63 # Python 3.x may behave better in this area
64 for h in data[0]:
65 data[0][h]["refs"] = self.internSet(data[0][h]["refs"])
66 data[0][h]["execs"] = self.internSet(data[0][h]["execs"])
67 for h in data[1]:
68 data[1][h]["execs"] = self.internSet(data[1][h]["execs"])
57 return 69 return
58 70
59 try: 71 def create_cachedata(self):
60 p = pickle.Unpickler(file(cachefile, "rb")) 72 data = [{}, {}]
61 data, version = p.load() 73 return data
62 except:
63 return
64 74
65 if version != PARSERCACHE_VERSION: 75codeparsercache = CodeParserCache()
66 return
67 76
68 pythonparsecache = data[0] 77def parser_cache_init(d):
69 shellparsecache = data[1] 78 codeparsercache.init_cache(d)
70 79
71def parser_cache_save(d): 80def parser_cache_save(d):
72 cachefile = parser_cachefile(d) 81 codeparsercache.save_extras(d)
73 if not cachefile:
74 return
75
76 glf = bb.utils.lockfile(cachefile + ".lock", shared=True)
77
78 i = os.getpid()
79 lf = None
80 while not lf:
81 shellcache = {}
82 pythoncache = {}
83
84 lf = bb.utils.lockfile(cachefile + ".lock." + str(i), retry=False)
85 if not lf or os.path.exists(cachefile + "-" + str(i)):
86 if lf:
87 bb.utils.unlockfile(lf)
88 lf = None
89 i = i + 1
90 continue
91
92 shellcache = shellparsecacheextras
93 pythoncache = pythonparsecacheextras
94
95 p = pickle.Pickler(file(cachefile + "-" + str(i), "wb"), -1)
96 p.dump([[pythoncache, shellcache], PARSERCACHE_VERSION])
97
98 bb.utils.unlockfile(lf)
99 bb.utils.unlockfile(glf)
100
101def internSet(items):
102 new = set()
103 for i in items:
104 new.add(intern(i))
105 return new
106 82
107def parser_cache_savemerge(d): 83def parser_cache_savemerge(d):
108 cachefile = parser_cachefile(d) 84 codeparsercache.save_merge(d)
109 if not cachefile:
110 return
111
112 glf = bb.utils.lockfile(cachefile + ".lock")
113
114 try:
115 p = pickle.Unpickler(file(cachefile, "rb"))
116 data, version = p.load()
117 except (IOError, EOFError):
118 data, version = None, None
119
120 if version != PARSERCACHE_VERSION:
121 data = [{}, {}]
122
123 for f in [y for y in os.listdir(os.path.dirname(cachefile)) if y.startswith(os.path.basename(cachefile) + '-')]:
124 f = os.path.join(os.path.dirname(cachefile), f)
125 try:
126 p = pickle.Unpickler(file(f, "rb"))
127 extradata, version = p.load()
128 except (IOError, EOFError):
129 extradata, version = [{}, {}], None
130
131 if version != PARSERCACHE_VERSION:
132 continue
133
134 for h in extradata[0]:
135 if h not in data[0]:
136 data[0][h] = extradata[0][h]
137 for h in extradata[1]:
138 if h not in data[1]:
139 data[1][h] = extradata[1][h]
140 os.unlink(f)
141
142 # When the dicts are originally created, python calls intern() on the set keys
143 # which significantly improves memory usage. Sadly the pickle/unpickle process
144 # doesn't call intern() on the keys and results in the same strings being duplicated
145 # in memory. This also means pickle will save the same string multiple times in
146 # the cache file. By interning the data here, the cache file shrinks dramatically
147 # meaning faster load times and the reloaded cache files also consume much less
148 # memory. This is worth any performance hit from this loops and the use of the
149 # intern() data storage.
150 # Python 3.x may behave better in this area
151 for h in data[0]:
152 data[0][h]["refs"] = internSet(data[0][h]["refs"])
153 data[0][h]["execs"] = internSet(data[0][h]["execs"])
154 for h in data[1]:
155 data[1][h]["execs"] = internSet(data[1][h]["execs"])
156
157 p = pickle.Pickler(file(cachefile, "wb"), -1)
158 p.dump([data, PARSERCACHE_VERSION])
159
160 bb.utils.unlockfile(glf)
161
162 85
163Logger = logging.getLoggerClass() 86Logger = logging.getLoggerClass()
164class BufferedLogger(Logger): 87class BufferedLogger(Logger):
@@ -235,14 +158,14 @@ class PythonParser():
235 def parse_python(self, node): 158 def parse_python(self, node):
236 h = hash(str(node)) 159 h = hash(str(node))
237 160
238 if h in pythonparsecache: 161 if h in codeparsercache.pythoncache:
239 self.references = pythonparsecache[h]["refs"] 162 self.references = codeparsercache.pythoncache[h]["refs"]
240 self.execs = pythonparsecache[h]["execs"] 163 self.execs = codeparsercache.pythoncache[h]["execs"]
241 return 164 return
242 165
243 if h in pythonparsecacheextras: 166 if h in codeparsercache.pythoncacheextras:
244 self.references = pythonparsecacheextras[h]["refs"] 167 self.references = codeparsercache.pythoncacheextras[h]["refs"]
245 self.execs = pythonparsecacheextras[h]["execs"] 168 self.execs = codeparsercache.pythoncacheextras[h]["execs"]
246 return 169 return
247 170
248 171
@@ -256,9 +179,9 @@ class PythonParser():
256 self.references.update(self.var_references) 179 self.references.update(self.var_references)
257 self.references.update(self.var_execs) 180 self.references.update(self.var_execs)
258 181
259 pythonparsecacheextras[h] = {} 182 codeparsercache.pythoncacheextras[h] = {}
260 pythonparsecacheextras[h]["refs"] = self.references 183 codeparsercache.pythoncacheextras[h]["refs"] = self.references
261 pythonparsecacheextras[h]["execs"] = self.execs 184 codeparsercache.pythoncacheextras[h]["execs"] = self.execs
262 185
263class ShellParser(): 186class ShellParser():
264 def __init__(self, name, log): 187 def __init__(self, name, log):
@@ -276,12 +199,12 @@ class ShellParser():
276 199
277 h = hash(str(value)) 200 h = hash(str(value))
278 201
279 if h in shellparsecache: 202 if h in codeparsercache.shellcache:
280 self.execs = shellparsecache[h]["execs"] 203 self.execs = codeparsercache.shellcache[h]["execs"]
281 return self.execs 204 return self.execs
282 205
283 if h in shellparsecacheextras: 206 if h in codeparsercache.shellcacheextras:
284 self.execs = shellparsecacheextras[h]["execs"] 207 self.execs = codeparsercache.shellcacheextras[h]["execs"]
285 return self.execs 208 return self.execs
286 209
287 try: 210 try:
@@ -293,8 +216,8 @@ class ShellParser():
293 self.process_tokens(token) 216 self.process_tokens(token)
294 self.execs = set(cmd for cmd in self.allexecs if cmd not in self.funcdefs) 217 self.execs = set(cmd for cmd in self.allexecs if cmd not in self.funcdefs)
295 218
296 shellparsecacheextras[h] = {} 219 codeparsercache.shellcacheextras[h] = {}
297 shellparsecacheextras[h]["execs"] = self.execs 220 codeparsercache.shellcacheextras[h]["execs"] = self.execs
298 221
299 return self.execs 222 return self.execs
300 223