mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
binman: Add basic support for debugging performance
One of binman's attributes is that it is extremely fast, at least for a Python program. Add some simple timing around operations that might take a while, such as reading an image and compressing it. This should help to maintain the performance as new features are added. This is for debugging purposes only. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
c31d0cb68c
commit
03ebc20de3
4 changed files with 88 additions and 0 deletions
|
@ -646,6 +646,9 @@ def Binman(args):
|
|||
|
||||
if missing:
|
||||
tout.Warning("\nSome images are invalid")
|
||||
|
||||
# Use this to debug the time take to pack the image
|
||||
#state.TimingShow()
|
||||
finally:
|
||||
tools.FinaliseOutputDir()
|
||||
finally:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#
|
||||
|
||||
from binman.entry import Entry
|
||||
from binman import state
|
||||
from dtoc import fdt_util
|
||||
from patman import tools
|
||||
from patman import tout
|
||||
|
@ -59,8 +60,12 @@ class Entry_blob(Entry):
|
|||
the data in chunks and avoid reading it all at once. For now
|
||||
this seems like an unnecessary complication.
|
||||
"""
|
||||
state.TimingStart('read')
|
||||
indata = tools.ReadFile(self._pathname)
|
||||
state.TimingAccum('read')
|
||||
state.TimingStart('compress')
|
||||
data = self.CompressData(indata)
|
||||
state.TimingAccum('compress')
|
||||
self.SetContents(data)
|
||||
return True
|
||||
|
||||
|
|
|
@ -4568,6 +4568,14 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertIn("Node '/binman/section@0': Timed out obtaining contents",
|
||||
str(e.exception))
|
||||
|
||||
def testTiming(self):
|
||||
"""Test output of timing information"""
|
||||
data = self._DoReadFile('055_sections.dts')
|
||||
with test_util.capture_sys_output() as (stdout, stderr):
|
||||
state.TimingShow()
|
||||
self.assertIn('read:', stdout.getvalue())
|
||||
self.assertIn('compress:', stdout.getvalue())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
# Holds and modifies the state information held by binman
|
||||
#
|
||||
|
||||
from collections import defaultdict
|
||||
import hashlib
|
||||
import re
|
||||
import time
|
||||
import threading
|
||||
|
||||
from dtoc import fdt
|
||||
|
@ -59,6 +61,27 @@ allow_entry_contraction = False
|
|||
# Number of threads to use for binman (None means machine-dependent)
|
||||
num_threads = None
|
||||
|
||||
|
||||
class Timing:
|
||||
"""Holds information about an operation that is being timed
|
||||
|
||||
Properties:
|
||||
name: Operation name (only one of each name is stored)
|
||||
start: Start time of operation in seconds (None if not start)
|
||||
accum:: Amount of time spent on this operation so far, in seconds
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.start = None # cause an error if TimingStart() is not called
|
||||
self.accum = 0.0
|
||||
|
||||
|
||||
# Holds timing info for each name:
|
||||
# key: name of Timing info (Timing.name)
|
||||
# value: Timing object
|
||||
timing_info = {}
|
||||
|
||||
|
||||
def GetFdtForEtype(etype):
|
||||
"""Get the Fdt object for a particular device-tree entry
|
||||
|
||||
|
@ -443,3 +466,52 @@ def GetThreads():
|
|||
Number of threads to use (None for default, 0 for single-threaded)
|
||||
"""
|
||||
return num_threads
|
||||
|
||||
def GetTiming(name):
|
||||
"""Get the timing info for a particular operation
|
||||
|
||||
The object is created if it does not already exist.
|
||||
|
||||
Args:
|
||||
name: Operation name to get
|
||||
|
||||
Returns:
|
||||
Timing object for the current thread
|
||||
"""
|
||||
threaded_name = '%s:%d' % (name, threading.get_ident())
|
||||
timing = timing_info.get(threaded_name)
|
||||
if not timing:
|
||||
timing = Timing(threaded_name)
|
||||
timing_info[threaded_name] = timing
|
||||
return timing
|
||||
|
||||
def TimingStart(name):
|
||||
"""Start the timer for an operation
|
||||
|
||||
Args:
|
||||
name: Operation name to start
|
||||
"""
|
||||
timing = GetTiming(name)
|
||||
timing.start = time.monotonic()
|
||||
|
||||
def TimingAccum(name):
|
||||
"""Stop and accumlate the time for an operation
|
||||
|
||||
This measures the time since the last TimingStart() and adds that to the
|
||||
accumulated time.
|
||||
|
||||
Args:
|
||||
name: Operation name to start
|
||||
"""
|
||||
timing = GetTiming(name)
|
||||
timing.accum += time.monotonic() - timing.start
|
||||
|
||||
def TimingShow():
|
||||
"""Show all timing information"""
|
||||
duration = defaultdict(float)
|
||||
for threaded_name, timing in timing_info.items():
|
||||
name = threaded_name.split(':')[0]
|
||||
duration[name] += timing.accum
|
||||
|
||||
for name, seconds in duration.items():
|
||||
print('%10s: %10.1fms' % (name, seconds * 1000))
|
||||
|
|
Loading…
Reference in a new issue