blob: 56e5bf8bc10f73f7b2a289c03a6748b01ee7f904 [file] [log] [blame]
Simon Glassc55a50f2018-09-14 04:57:19 -06001# SPDX-License-Identifier: GPL-2.0+
2# Copyright 2018 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
5# Holds and modifies the state information held by binman
6#
7
Simon Glass03ebc202021-07-06 10:36:41 -06008from collections import defaultdict
Simon Glasse0e5df92018-09-14 04:57:31 -06009import hashlib
Simon Glassc55a50f2018-09-14 04:57:19 -060010import re
Simon Glass03ebc202021-07-06 10:36:41 -060011import time
Simon Glassc69d19c2021-07-06 10:36:37 -060012import threading
Simon Glassc55a50f2018-09-14 04:57:19 -060013
Simon Glass16287932020-04-17 18:09:03 -060014from dtoc import fdt
Simon Glassc55a50f2018-09-14 04:57:19 -060015import os
Simon Glassbf776672020-04-17 18:09:04 -060016from patman import tools
17from patman import tout
Simon Glassc55a50f2018-09-14 04:57:19 -060018
Simon Glassc475dec2021-11-23 11:03:42 -070019OUR_PATH = os.path.dirname(os.path.realpath(__file__))
20
Simon Glass76971702021-03-18 20:25:00 +130021# Map an dtb etype to its expected filename
22DTB_TYPE_FNAME = {
23 'u-boot-spl-dtb': 'spl/u-boot-spl.dtb',
24 'u-boot-tpl-dtb': 'tpl/u-boot-tpl.dtb',
Simon Glass6ad24522022-02-28 07:16:54 -070025 'u-boot-vpl-dtb': 'vpl/u-boot-vpl.dtb',
Simon Glass76971702021-03-18 20:25:00 +130026 }
27
Simon Glassfb5e8b12019-07-20 12:23:32 -060028# Records the device-tree files known to binman, keyed by entry type (e.g.
29# 'u-boot-spl-dtb'). These are the output FDT files, which can be updated by
30# binman. They have been copied to <xxx>.out files.
31#
Simon Glasscb8bebb2021-03-18 20:25:01 +130032# key: entry type (e.g. 'u-boot-dtb)
Simon Glassfb5e8b12019-07-20 12:23:32 -060033# value: tuple:
34# Fdt object
35# Filename
Simon Glass6ca0dcb2019-07-20 12:23:43 -060036output_fdt_info = {}
Simon Glassc55a50f2018-09-14 04:57:19 -060037
Simon Glass10f9d002019-07-20 12:23:50 -060038# Prefix to add to an fdtmap path to turn it into a path to the /binman node
39fdt_path_prefix = ''
40
Simon Glassc55a50f2018-09-14 04:57:19 -060041# Arguments passed to binman to provide arguments to entries
42entry_args = {}
43
Simon Glass539aece2018-09-14 04:57:22 -060044# True to use fake device-tree files for testing (see U_BOOT_DTB_DATA in
45# ftest.py)
Simon Glass93d17412018-09-14 04:57:23 -060046use_fake_dtb = False
Simon Glass539aece2018-09-14 04:57:22 -060047
Simon Glass2a72cc72018-09-14 04:57:20 -060048# The DTB which contains the full image information
49main_dtb = None
50
Simon Glassbf6906b2019-07-08 14:25:36 -060051# Allow entries to expand after they have been packed. This is detected and
52# forces a re-pack. If not allowed, any attempted expansion causes an error in
53# Entry.ProcessContentsUpdate()
54allow_entry_expansion = True
55
Simon Glass61ec04f2019-07-20 12:23:58 -060056# Don't allow entries to contract after they have been packed. Instead just
57# leave some wasted space. If allowed, this is detected and forces a re-pack,
58# but may result in entries that oscillate in size, thus causing a pack error.
59# An example is a compressed device tree where the original offset values
60# result in a larger compressed size than the new ones, but then after updating
61# to the new ones, the compressed size increases, etc.
62allow_entry_contraction = False
63
Simon Glassc69d19c2021-07-06 10:36:37 -060064# Number of threads to use for binman (None means machine-dependent)
65num_threads = None
66
Simon Glass03ebc202021-07-06 10:36:41 -060067
68class Timing:
69 """Holds information about an operation that is being timed
70
71 Properties:
72 name: Operation name (only one of each name is stored)
73 start: Start time of operation in seconds (None if not start)
74 accum:: Amount of time spent on this operation so far, in seconds
75 """
76 def __init__(self, name):
77 self.name = name
78 self.start = None # cause an error if TimingStart() is not called
79 self.accum = 0.0
80
81
82# Holds timing info for each name:
83# key: name of Timing info (Timing.name)
84# value: Timing object
85timing_info = {}
86
87
Simon Glassfb5e8b12019-07-20 12:23:32 -060088def GetFdtForEtype(etype):
89 """Get the Fdt object for a particular device-tree entry
Simon Glassc55a50f2018-09-14 04:57:19 -060090
91 Binman keeps track of at least one device-tree file called u-boot.dtb but
92 can also have others (e.g. for SPL). This function looks up the given
Simon Glassfb5e8b12019-07-20 12:23:32 -060093 entry and returns the associated Fdt object.
Simon Glassc55a50f2018-09-14 04:57:19 -060094
95 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -060096 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -060097
98 Returns:
Simon Glassfb5e8b12019-07-20 12:23:32 -060099 Fdt object associated with the entry type
Simon Glassc55a50f2018-09-14 04:57:19 -0600100 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600101 value = output_fdt_info.get(etype);
Simon Glass6a3b5b52019-07-20 12:23:42 -0600102 if not value:
103 return None
104 return value[0]
Simon Glassc55a50f2018-09-14 04:57:19 -0600105
Simon Glassfb5e8b12019-07-20 12:23:32 -0600106def GetFdtPath(etype):
Simon Glassc55a50f2018-09-14 04:57:19 -0600107 """Get the full pathname of a particular Fdt object
108
Simon Glass726e2962019-07-20 12:23:30 -0600109 Similar to GetFdtForEtype() but returns the pathname associated with the
110 Fdt.
Simon Glassc55a50f2018-09-14 04:57:19 -0600111
112 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -0600113 etype: Entry type of device tree (e.g. 'u-boot-dtb')
Simon Glassc55a50f2018-09-14 04:57:19 -0600114
115 Returns:
116 Full path name to the associated Fdt
117 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600118 return output_fdt_info[etype][0]._fname
Simon Glassc55a50f2018-09-14 04:57:19 -0600119
Simon Glassfb5e8b12019-07-20 12:23:32 -0600120def GetFdtContents(etype='u-boot-dtb'):
Simon Glass6ed45ba2018-09-14 04:57:24 -0600121 """Looks up the FDT pathname and contents
122
123 This is used to obtain the Fdt pathname and contents when needed by an
124 entry. It supports a 'fake' dtb, allowing tests to substitute test data for
125 the real dtb.
126
127 Args:
Simon Glassfb5e8b12019-07-20 12:23:32 -0600128 etype: Entry type to look up (e.g. 'u-boot.dtb').
Simon Glass6ed45ba2018-09-14 04:57:24 -0600129
130 Returns:
131 tuple:
132 pathname to Fdt
133 Fdt data (as bytes)
134 """
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600135 if etype not in output_fdt_info:
Simon Glass6a3b5b52019-07-20 12:23:42 -0600136 return None, None
137 if not use_fake_dtb:
Simon Glassfb5e8b12019-07-20 12:23:32 -0600138 pathname = GetFdtPath(etype)
139 data = GetFdtForEtype(etype).GetContents()
Simon Glass6ed45ba2018-09-14 04:57:24 -0600140 else:
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600141 fname = output_fdt_info[etype][1]
Simon Glassc1aa66e2022-01-29 14:14:04 -0700142 pathname = tools.get_input_filename(fname)
143 data = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600144 return pathname, data
145
Simon Glassf6e02492019-07-20 12:24:08 -0600146def UpdateFdtContents(etype, data):
147 """Update the contents of a particular device tree
148
149 The device tree is updated and written back to its file. This affects what
150 is returned from future called to GetFdtContents(), etc.
151
152 Args:
153 etype: Entry type (e.g. 'u-boot-dtb')
154 data: Data to replace the DTB with
155 """
Simon Glasscb8bebb2021-03-18 20:25:01 +1300156 dtb, fname = output_fdt_info[etype]
Simon Glassf6e02492019-07-20 12:24:08 -0600157 dtb_fname = dtb.GetFilename()
Simon Glassc1aa66e2022-01-29 14:14:04 -0700158 tools.write_file(dtb_fname, data)
Simon Glassf6e02492019-07-20 12:24:08 -0600159 dtb = fdt.FdtScan(dtb_fname)
Simon Glasscb8bebb2021-03-18 20:25:01 +1300160 output_fdt_info[etype] = [dtb, fname]
Simon Glassf6e02492019-07-20 12:24:08 -0600161
Simon Glassc55a50f2018-09-14 04:57:19 -0600162def SetEntryArgs(args):
163 """Set the value of the entry args
164
165 This sets up the entry_args dict which is used to supply entry arguments to
166 entries.
167
168 Args:
169 args: List of entry arguments, each in the format "name=value"
170 """
171 global entry_args
172
173 entry_args = {}
Simon Glassf3385a52022-01-29 14:14:15 -0700174 tout.debug('Processing entry args:')
Simon Glassc55a50f2018-09-14 04:57:19 -0600175 if args:
176 for arg in args:
177 m = re.match('([^=]*)=(.*)', arg)
178 if not m:
179 raise ValueError("Invalid entry arguemnt '%s'" % arg)
Simon Glass06684922021-03-18 20:25:07 +1300180 name, value = m.groups()
Simon Glassf3385a52022-01-29 14:14:15 -0700181 tout.debug(' %20s = %s' % (name, value))
Simon Glass06684922021-03-18 20:25:07 +1300182 entry_args[name] = value
Simon Glassf3385a52022-01-29 14:14:15 -0700183 tout.debug('Processing entry args done')
Simon Glassc55a50f2018-09-14 04:57:19 -0600184
185def GetEntryArg(name):
186 """Get the value of an entry argument
187
188 Args:
189 name: Name of argument to retrieve
190
191 Returns:
192 String value of argument
193 """
194 return entry_args.get(name)
Simon Glass2a72cc72018-09-14 04:57:20 -0600195
Simon Glass06684922021-03-18 20:25:07 +1300196def GetEntryArgBool(name):
197 """Get the value of an entry argument as a boolean
198
199 Args:
200 name: Name of argument to retrieve
201
202 Returns:
203 False if the entry argument is consider False (empty, '0' or 'n'), else
204 True
205 """
206 val = GetEntryArg(name)
207 return val and val not in ['n', '0']
208
Simon Glass539aece2018-09-14 04:57:22 -0600209def Prepare(images, dtb):
Simon Glass2a72cc72018-09-14 04:57:20 -0600210 """Get device tree files ready for use
211
Simon Glass4bdd1152019-07-20 12:23:29 -0600212 This sets up a set of device tree files that can be retrieved by
213 GetAllFdts(). This includes U-Boot proper and any SPL device trees.
Simon Glass2a72cc72018-09-14 04:57:20 -0600214
215 Args:
Simon Glass539aece2018-09-14 04:57:22 -0600216 images: List of images being used
Simon Glass2a72cc72018-09-14 04:57:20 -0600217 dtb: Main dtb
218 """
Simon Glass10f9d002019-07-20 12:23:50 -0600219 global output_fdt_info, main_dtb, fdt_path_prefix
Simon Glass2a72cc72018-09-14 04:57:20 -0600220 # Import these here in case libfdt.py is not available, in which case
221 # the above help option still works.
Simon Glass16287932020-04-17 18:09:03 -0600222 from dtoc import fdt
223 from dtoc import fdt_util
Simon Glass2a72cc72018-09-14 04:57:20 -0600224
225 # If we are updating the DTBs we need to put these updated versions
226 # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb'
227 # since it is assumed to be the one passed in with options.dt, and
228 # was handled just above.
229 main_dtb = dtb
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600230 output_fdt_info.clear()
Simon Glass10f9d002019-07-20 12:23:50 -0600231 fdt_path_prefix = ''
Simon Glasscb8bebb2021-03-18 20:25:01 +1300232 output_fdt_info['u-boot-dtb'] = [dtb, 'u-boot.dtb']
Simon Glass76971702021-03-18 20:25:00 +1300233 if use_fake_dtb:
234 for etype, fname in DTB_TYPE_FNAME.items():
Simon Glasscb8bebb2021-03-18 20:25:01 +1300235 output_fdt_info[etype] = [dtb, fname]
Simon Glass76971702021-03-18 20:25:00 +1300236 else:
Simon Glassf49462e2019-07-20 12:23:34 -0600237 fdt_set = {}
Simon Glass5187b802021-03-18 20:25:03 +1300238 for etype, fname in DTB_TYPE_FNAME.items():
Simon Glassc1aa66e2022-01-29 14:14:04 -0700239 infile = tools.get_input_filename(fname, allow_missing=True)
Simon Glass5187b802021-03-18 20:25:03 +1300240 if infile and os.path.exists(infile):
241 fname_dtb = fdt_util.EnsureCompiled(infile)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700242 out_fname = tools.get_output_filename('%s.out' %
Simon Glass5187b802021-03-18 20:25:03 +1300243 os.path.split(fname)[1])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700244 tools.write_file(out_fname, tools.read_file(fname_dtb))
Simon Glass5187b802021-03-18 20:25:03 +1300245 other_dtb = fdt.FdtScan(out_fname)
246 output_fdt_info[etype] = [other_dtb, out_fname]
247
Simon Glass2a72cc72018-09-14 04:57:20 -0600248
Simon Glass10f9d002019-07-20 12:23:50 -0600249def PrepareFromLoadedData(image):
250 """Get device tree files ready for use with a loaded image
251
252 Loaded images are different from images that are being created by binman,
253 since there is generally already an fdtmap and we read the description from
254 that. This provides the position and size of every entry in the image with
255 no calculation required.
256
257 This function uses the same output_fdt_info[] as Prepare(). It finds the
258 device tree files, adds a reference to the fdtmap and sets the FDT path
259 prefix to translate from the fdtmap (where the root node is the image node)
260 to the normal device tree (where the image node is under a /binman node).
261
262 Args:
263 images: List of images being used
264 """
265 global output_fdt_info, main_dtb, fdt_path_prefix
266
Simon Glassf3385a52022-01-29 14:14:15 -0700267 tout.info('Preparing device trees')
Simon Glass10f9d002019-07-20 12:23:50 -0600268 output_fdt_info.clear()
269 fdt_path_prefix = ''
Simon Glasscb8bebb2021-03-18 20:25:01 +1300270 output_fdt_info['fdtmap'] = [image.fdtmap_dtb, 'u-boot.dtb']
Simon Glass10f9d002019-07-20 12:23:50 -0600271 main_dtb = None
Simon Glassf3385a52022-01-29 14:14:15 -0700272 tout.info(" Found device tree type 'fdtmap' '%s'" % image.fdtmap_dtb.name)
Simon Glass10f9d002019-07-20 12:23:50 -0600273 for etype, value in image.GetFdts().items():
274 entry, fname = value
Simon Glassc1aa66e2022-01-29 14:14:04 -0700275 out_fname = tools.get_output_filename('%s.dtb' % entry.etype)
Simon Glassf3385a52022-01-29 14:14:15 -0700276 tout.info(" Found device tree type '%s' at '%s' path '%s'" %
Simon Glass10f9d002019-07-20 12:23:50 -0600277 (etype, out_fname, entry.GetPath()))
278 entry._filename = entry.GetDefaultFilename()
279 data = entry.ReadData()
280
Simon Glassc1aa66e2022-01-29 14:14:04 -0700281 tools.write_file(out_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -0600282 dtb = fdt.Fdt(out_fname)
283 dtb.Scan()
284 image_node = dtb.GetNode('/binman')
285 if 'multiple-images' in image_node.props:
286 image_node = dtb.GetNode('/binman/%s' % image.image_node)
287 fdt_path_prefix = image_node.path
Simon Glasscb8bebb2021-03-18 20:25:01 +1300288 output_fdt_info[etype] = [dtb, None]
Simon Glassf3385a52022-01-29 14:14:15 -0700289 tout.info(" FDT path prefix '%s'" % fdt_path_prefix)
Simon Glass10f9d002019-07-20 12:23:50 -0600290
291
Simon Glass4bdd1152019-07-20 12:23:29 -0600292def GetAllFdts():
Simon Glass2a72cc72018-09-14 04:57:20 -0600293 """Yield all device tree files being used by binman
294
295 Yields:
Simon Glass6ad24522022-02-28 07:16:54 -0700296 Device trees being used (U-Boot proper, SPL, TPL, VPL)
Simon Glass2a72cc72018-09-14 04:57:20 -0600297 """
Simon Glass10f9d002019-07-20 12:23:50 -0600298 if main_dtb:
299 yield main_dtb
Simon Glass6ca0dcb2019-07-20 12:23:43 -0600300 for etype in output_fdt_info:
301 dtb = output_fdt_info[etype][0]
Simon Glass77e4ef12019-07-20 12:23:33 -0600302 if dtb != main_dtb:
303 yield dtb
Simon Glass2a72cc72018-09-14 04:57:20 -0600304
Simon Glass12bb1a92019-07-20 12:23:51 -0600305def GetUpdateNodes(node, for_repack=False):
Simon Glassf46621d2018-09-14 04:57:21 -0600306 """Yield all the nodes that need to be updated in all device trees
307
308 The property referenced by this node is added to any device trees which
309 have the given node. Due to removable of unwanted notes, SPL and TPL may
310 not have this node.
311
312 Args:
313 node: Node object in the main device tree to look up
Simon Glass12bb1a92019-07-20 12:23:51 -0600314 for_repack: True if we want only nodes which need 'repack' properties
315 added to them (e.g. 'orig-offset'), False to return all nodes. We
316 don't add repack properties to SPL/TPL device trees.
Simon Glassf46621d2018-09-14 04:57:21 -0600317
318 Yields:
319 Node objects in each device tree that is in use (U-Boot proper, which
320 is node, SPL and TPL)
321 """
322 yield node
Simon Glasscb8bebb2021-03-18 20:25:01 +1300323 for entry_type, (dtb, fname) in output_fdt_info.items():
Simon Glass6ed45ba2018-09-14 04:57:24 -0600324 if dtb != node.GetFdt():
Simon Glasscb8bebb2021-03-18 20:25:01 +1300325 if for_repack and entry_type != 'u-boot-dtb':
Simon Glass12bb1a92019-07-20 12:23:51 -0600326 continue
Simon Glass10f9d002019-07-20 12:23:50 -0600327 other_node = dtb.GetNode(fdt_path_prefix + node.path)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600328 if other_node:
329 yield other_node
Simon Glassf46621d2018-09-14 04:57:21 -0600330
Simon Glass12bb1a92019-07-20 12:23:51 -0600331def AddZeroProp(node, prop, for_repack=False):
Simon Glassf46621d2018-09-14 04:57:21 -0600332 """Add a new property to affected device trees with an integer value of 0.
333
334 Args:
335 prop_name: Name of property
Simon Glass12bb1a92019-07-20 12:23:51 -0600336 for_repack: True is this property is only needed for repacking
Simon Glassf46621d2018-09-14 04:57:21 -0600337 """
Simon Glass12bb1a92019-07-20 12:23:51 -0600338 for n in GetUpdateNodes(node, for_repack):
Simon Glassf46621d2018-09-14 04:57:21 -0600339 n.AddZeroProp(prop)
340
Simon Glass0a98b282018-09-14 04:57:28 -0600341def AddSubnode(node, name):
342 """Add a new subnode to a node in affected device trees
343
344 Args:
345 node: Node to add to
346 name: name of node to add
347
348 Returns:
349 New subnode that was created in main tree
350 """
351 first = None
352 for n in GetUpdateNodes(node):
353 subnode = n.AddSubnode(name)
354 if not first:
355 first = subnode
356 return first
357
358def AddString(node, prop, value):
359 """Add a new string property to affected device trees
360
361 Args:
362 prop_name: Name of property
363 value: String value (which will be \0-terminated in the DT)
364 """
365 for n in GetUpdateNodes(node):
366 n.AddString(prop, value)
367
Simon Glass6eb99322021-01-06 21:35:18 -0700368def AddInt(node, prop, value):
369 """Add a new string property to affected device trees
370
371 Args:
372 prop_name: Name of property
373 val: Integer value of property
374 """
375 for n in GetUpdateNodes(node):
376 n.AddInt(prop, value)
377
Simon Glass12bb1a92019-07-20 12:23:51 -0600378def SetInt(node, prop, value, for_repack=False):
Simon Glassf46621d2018-09-14 04:57:21 -0600379 """Update an integer property in affected device trees with an integer value
380
381 This is not allowed to change the size of the FDT.
382
383 Args:
384 prop_name: Name of property
Simon Glass12bb1a92019-07-20 12:23:51 -0600385 for_repack: True is this property is only needed for repacking
Simon Glassf46621d2018-09-14 04:57:21 -0600386 """
Simon Glass12bb1a92019-07-20 12:23:51 -0600387 for n in GetUpdateNodes(node, for_repack):
Simon Glassf3385a52022-01-29 14:14:15 -0700388 tout.detail("File %s: Update node '%s' prop '%s' to %#x" %
Simon Glass51014aa2019-07-20 12:23:56 -0600389 (n.GetFdt().name, n.path, prop, value))
Simon Glassf46621d2018-09-14 04:57:21 -0600390 n.SetInt(prop, value)
Simon Glasse0e5df92018-09-14 04:57:31 -0600391
392def CheckAddHashProp(node):
393 hash_node = node.FindNode('hash')
394 if hash_node:
395 algo = hash_node.props.get('algo')
396 if not algo:
397 return "Missing 'algo' property for hash node"
398 if algo.value == 'sha256':
399 size = 32
400 else:
Simon Glass8db1f992022-02-08 10:59:44 -0700401 return "Unknown hash algorithm '%s'" % algo.value
Simon Glasse0e5df92018-09-14 04:57:31 -0600402 for n in GetUpdateNodes(hash_node):
403 n.AddEmptyProp('value', size)
404
405def CheckSetHashValue(node, get_data_func):
406 hash_node = node.FindNode('hash')
407 if hash_node:
408 algo = hash_node.props.get('algo').value
409 if algo == 'sha256':
410 m = hashlib.sha256()
411 m.update(get_data_func())
412 data = m.digest()
413 for n in GetUpdateNodes(hash_node):
414 n.SetData('value', data)
Simon Glassbf6906b2019-07-08 14:25:36 -0600415
416def SetAllowEntryExpansion(allow):
417 """Set whether post-pack expansion of entries is allowed
418
419 Args:
420 allow: True to allow expansion, False to raise an exception
421 """
422 global allow_entry_expansion
423
424 allow_entry_expansion = allow
425
426def AllowEntryExpansion():
427 """Check whether post-pack expansion of entries is allowed
428
429 Returns:
430 True if expansion should be allowed, False if an exception should be
431 raised
432 """
433 return allow_entry_expansion
Simon Glass61ec04f2019-07-20 12:23:58 -0600434
435def SetAllowEntryContraction(allow):
436 """Set whether post-pack contraction of entries is allowed
437
438 Args:
439 allow: True to allow contraction, False to raise an exception
440 """
441 global allow_entry_contraction
442
443 allow_entry_contraction = allow
444
445def AllowEntryContraction():
446 """Check whether post-pack contraction of entries is allowed
447
448 Returns:
449 True if contraction should be allowed, False if an exception should be
450 raised
451 """
452 return allow_entry_contraction
Simon Glassc69d19c2021-07-06 10:36:37 -0600453
454def SetThreads(threads):
455 """Set the number of threads to use when building sections
456
457 Args:
458 threads: Number of threads to use (None for default, 0 for
459 single-threaded)
460 """
461 global num_threads
462
463 num_threads = threads
464
465def GetThreads():
466 """Get the number of threads to use when building sections
467
468 Returns:
469 Number of threads to use (None for default, 0 for single-threaded)
470 """
471 return num_threads
Simon Glass03ebc202021-07-06 10:36:41 -0600472
473def GetTiming(name):
474 """Get the timing info for a particular operation
475
476 The object is created if it does not already exist.
477
478 Args:
479 name: Operation name to get
480
481 Returns:
482 Timing object for the current thread
483 """
484 threaded_name = '%s:%d' % (name, threading.get_ident())
485 timing = timing_info.get(threaded_name)
486 if not timing:
487 timing = Timing(threaded_name)
488 timing_info[threaded_name] = timing
489 return timing
490
491def TimingStart(name):
492 """Start the timer for an operation
493
494 Args:
495 name: Operation name to start
496 """
497 timing = GetTiming(name)
498 timing.start = time.monotonic()
499
500def TimingAccum(name):
501 """Stop and accumlate the time for an operation
502
503 This measures the time since the last TimingStart() and adds that to the
504 accumulated time.
505
506 Args:
507 name: Operation name to start
508 """
509 timing = GetTiming(name)
510 timing.accum += time.monotonic() - timing.start
511
512def TimingShow():
513 """Show all timing information"""
514 duration = defaultdict(float)
515 for threaded_name, timing in timing_info.items():
516 name = threaded_name.split(':')[0]
517 duration[name] += timing.accum
518
519 for name, seconds in duration.items():
520 print('%10s: %10.1fms' % (name, seconds * 1000))
Simon Glassc475dec2021-11-23 11:03:42 -0700521
522def GetVersion(path=OUR_PATH):
523 """Get the version string for binman
524
525 Args:
526 path: Path to 'version' file
527
528 Returns:
529 str: String version, e.g. 'v2021.10'
530 """
531 version_fname = os.path.join(path, 'version')
532 if os.path.exists(version_fname):
Simon Glassc1aa66e2022-01-29 14:14:04 -0700533 version = tools.read_file(version_fname, binary=False)
Simon Glassc475dec2021-11-23 11:03:42 -0700534 else:
535 version = '(unreleased)'
536 return version