summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2015-07-24 11:40:55 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-07-24 23:28:35 +0100
commit9901415ecd11df0da73fccd867c4f1ba39abc9ab (patch)
tree1032349b26f2d3b83722620759be461150f4b3ea
parent67c6cc854f0add255a0559b9104c83b5d2ffde64 (diff)
downloadpoky-9901415ecd11df0da73fccd867c4f1ba39abc9ab.tar.gz
bitbake: data_smart: Improve performance of infer_caller_details()
As things stand now, bitbake -e (which turns on all the caller tracking) of OE-Core generates around 9.5 million stat calls which is slow and the largest single thing on the profile data. This is because infer_caller_details() calls traceback.extract_stack() which adds line contents to the traceback. This in turn calls python's internal linecache code which calls stat on every file for every callback. We don't even use that info. We only even want a single frame of the stack. Instead, open code for the pieces of information we need. Also, only obtain the stack once for both halves of the infer_caller_details() code. This reduces the number of stat calls to around 0.5 million and significantly improves parsing with bitbake -e. (Bitbake rev: 7be76d8f79ea92fd4bd36146eb9a4b86551b526d) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--bitbake/lib/bb/data_smart.py25
1 files changed, 17 insertions, 8 deletions
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py
index a7cae77d36..f0187b7a17 100644
--- a/bitbake/lib/bb/data_smart.py
+++ b/bitbake/lib/bb/data_smart.py
@@ -54,27 +54,36 @@ def infer_caller_details(loginfo, parent = False, varval = True):
54 return 54 return
55 # Infer caller's likely values for variable (var) and value (value), 55 # Infer caller's likely values for variable (var) and value (value),
56 # to reduce clutter in the rest of the code. 56 # to reduce clutter in the rest of the code.
57 if varval and ('variable' not in loginfo or 'detail' not in loginfo): 57 above = None
58 def set_above():
58 try: 59 try:
59 raise Exception 60 raise Exception
60 except Exception: 61 except Exception:
61 tb = sys.exc_info()[2] 62 tb = sys.exc_info()[2]
62 if parent: 63 if parent:
63 above = tb.tb_frame.f_back.f_back 64 return tb.tb_frame.f_back.f_back.f_back
64 else: 65 else:
65 above = tb.tb_frame.f_back 66 return tb.tb_frame.f_back.f_back
66 lcls = above.f_locals.items() 67
68 if varval and ('variable' not in loginfo or 'detail' not in loginfo):
69 if not above:
70 above = set_above()
71 lcls = above.f_locals.items()
67 for k, v in lcls: 72 for k, v in lcls:
68 if k == 'value' and 'detail' not in loginfo: 73 if k == 'value' and 'detail' not in loginfo:
69 loginfo['detail'] = v 74 loginfo['detail'] = v
70 if k == 'var' and 'variable' not in loginfo: 75 if k == 'var' and 'variable' not in loginfo:
71 loginfo['variable'] = v 76 loginfo['variable'] = v
72 # Infer file/line/function from traceback 77 # Infer file/line/function from traceback
78 # Don't use traceback.extract_stack() since it fills the line contents which
79 # we don't need and that hits stat syscalls
73 if 'file' not in loginfo: 80 if 'file' not in loginfo:
74 depth = 3 81 if not above:
75 if parent: 82 above = set_above()
76 depth = 4 83 f = above.f_back
77 file, line, func, text = traceback.extract_stack(limit = depth)[0] 84 line = f.f_lineno
85 file = f.f_code.co_filename
86 func = f.f_code.co_name
78 loginfo['file'] = file 87 loginfo['file'] = file
79 loginfo['line'] = line 88 loginfo['line'] = line
80 if func not in loginfo: 89 if func not in loginfo: