summaryrefslogtreecommitdiff
path: root/build-aux/measurestack
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-31 15:58:51 -0600
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-04-01 05:09:44 -0600
commit2ced5e02eacfc6b9e67435fe3a24dcb6c3a29037 (patch)
treea228eef90a7000c80dab582630b85d04dac923ee /build-aux/measurestack
parent1a0c67835cd74c6bf2113bb14a7f1b520508c536 (diff)
measurestack: Compile all regexes upfront
Diffstat (limited to 'build-aux/measurestack')
-rw-r--r--build-aux/measurestack/__init__.py5
-rw-r--r--build-aux/measurestack/analyze.py19
-rw-r--r--build-aux/measurestack/app_plugins.py56
-rw-r--r--build-aux/measurestack/util.py4
-rw-r--r--build-aux/measurestack/vcg.py18
5 files changed, 55 insertions, 47 deletions
diff --git a/build-aux/measurestack/__init__.py b/build-aux/measurestack/__init__.py
index b38a3c8..c1b9d7f 100644
--- a/build-aux/measurestack/__init__.py
+++ b/build-aux/measurestack/__init__.py
@@ -14,13 +14,14 @@ __all__ = [
]
+re_c_obj_suffix = re.compile(r"\.c\.(?:o|obj)$")
+
+
def main() -> None:
pico_platform = sys.argv[1]
base_dir = sys.argv[2]
obj_fnames = set(sys.argv[3:])
- re_c_obj_suffix = re.compile(r"\.c\.(?:o|obj)$")
-
c_fnames: set[str] = set()
ci_fnames: set[str] = set()
for obj_fname in obj_fnames:
diff --git a/build-aux/measurestack/analyze.py b/build-aux/measurestack/analyze.py
index 45ac876..871ff2d 100644
--- a/build-aux/measurestack/analyze.py
+++ b/build-aux/measurestack/analyze.py
@@ -133,6 +133,16 @@ class Application(typing.Protocol):
def skip_call(self, chain: typing.Sequence[QName], funcname: QName) -> bool: ...
+re_node_label = re.compile(
+ r"(?P<funcname>[^\n]+)\n"
+ + r"(?P<location>[^\n]+:[0-9]+:[0-9]+)\n"
+ + r"(?P<nstatic>[0-9]+) bytes \((?P<usage_kind>static|dynamic|dynamic,bounded)\)\n"
+ + r"(?P<ndynamic>[0-9]+) dynamic objects"
+ + r"(?:\n.*)*",
+ flags=re.MULTILINE,
+)
+
+
def analyze(
*,
ci_fnames: typing.Collection[str],
@@ -140,15 +150,6 @@ def analyze(
app: Application,
cfg_max_call_depth: int,
) -> AnalyzeResult:
- re_node_label = re.compile(
- r"(?P<funcname>[^\n]+)\n"
- + r"(?P<location>[^\n]+:[0-9]+:[0-9]+)\n"
- + r"(?P<nstatic>[0-9]+) bytes \((?P<usage_kind>static|dynamic|dynamic,bounded)\)\n"
- + r"(?P<ndynamic>[0-9]+) dynamic objects"
- + r"(?:\n.*)*",
- flags=re.MULTILINE,
- )
-
graph: dict[QName, Node] = {}
qualified: dict[BaseName, set[QName]] = {}
diff --git a/build-aux/measurestack/app_plugins.py b/build-aux/measurestack/app_plugins.py
index eb1db09..0bd5486 100644
--- a/build-aux/measurestack/app_plugins.py
+++ b/build-aux/measurestack/app_plugins.py
@@ -55,15 +55,21 @@ class CmdPlugin:
return False
+re_comment = re.compile(r"/\*.*?\*/")
+re_ws = re.compile(r"\s+")
+re_lo_iface = re.compile(r"^\s*#\s*define\s+(?P<name>\S+)_LO_IFACE")
+re_lo_func = re.compile(r"LO_FUNC *\([^,]*, *(?P<name>[^,) ]+) *[,)]")
+re_lo_implementation = re.compile(
+ r"^LO_IMPLEMENTATION_[HC]\s*\(\s*(?P<iface>[^, ]+)\s*,\s*(?P<impl_typ>[^,]+)\s*,\s*(?P<impl_name>[^, ]+)\s*[,)].*"
+)
+re_call_objcall = re.compile(r"LO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*")
+
+
class LibObjPlugin:
objcalls: dict[str, set[QName]] # method_name => {method_impls}
def __init__(self, arg_c_fnames: typing.Collection[str]) -> None:
ifaces: dict[str, set[str]] = {} # iface_name => {method_names}
- re_comment = re.compile(r"/\*.*?\*/")
- re_ws = re.compile(r"\s+")
- re_lo_iface = re.compile(r"^\s*#\s*define\s+(?P<name>\S+)_LO_IFACE")
- re_lo_func = re.compile(r"LO_FUNC *\([^,]*, *(?P<name>[^,) ]+) *[,)]")
for fname in arg_c_fnames:
with open(fname, "r", encoding="utf-8") as fh:
while line := fh.readline():
@@ -82,9 +88,6 @@ class LibObjPlugin:
implementations: dict[str, set[str]] = {} # iface_name => {impl_names}
for iface_name in ifaces:
implementations[iface_name] = set()
- re_lo_implementation = re.compile(
- r"^LO_IMPLEMENTATION_[HC]\s*\(\s*(?P<iface>[^, ]+)\s*,\s*(?P<impl_typ>[^,]+)\s*,\s*(?P<impl_name>[^, ]+)\s*[,)].*"
- )
for fname in arg_c_fnames:
with open(fname, "r", encoding="utf-8") as fh:
for line in fh:
@@ -116,7 +119,6 @@ class LibObjPlugin:
def indirect_callees(
self, loc: str, line: str
) -> tuple[typing.Collection[QName], bool] | None:
- re_call_objcall = re.compile(r"LO_CALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*")
if "/3rd-party/" in loc:
return None
@@ -254,6 +256,15 @@ class LibCRIPCPlugin:
return False
+re_tmessage_handler = re.compile(
+ r"^\s*\[LIB9P_TYP_T[^]]+\]\s*=\s*\(tmessage_handler\)\s*(?P<handler>\S+),\s*$"
+)
+re_lib9p_msg_entry = re.compile(r"^\s*_MSG_(?:[A-Z]+)\((?P<typ>\S+)\),$")
+re_lib9p_caller = re.compile(
+ r"^lib9p_(?P<grp>[TR])msg_(?P<meth>validate|unmarshal|marshal)$"
+)
+
+
class Lib9PPlugin:
tmessage_handlers: set[QName] | None
lib9p_msgs: set[str]
@@ -303,9 +314,6 @@ class Lib9PPlugin:
tmessage_handlers: set[QName] | None = None
if lib9p_srv_c_fname:
- re_tmessage_handler = re.compile(
- r"^\s*\[LIB9P_TYP_T[^]]+\]\s*=\s*\(tmessage_handler\)\s*(?P<handler>\S+),\s*$"
- )
tmessage_handlers = set()
with open(lib9p_srv_c_fname, "r", encoding="utf-8") as fh:
for line in fh:
@@ -316,7 +324,6 @@ class Lib9PPlugin:
lib9p_msgs: set[str] = set()
if lib9p_generated_c_fname:
- re_lib9p_msg_entry = re.compile(r"^\s*_MSG_(?:[A-Z]+)\((?P<typ>\S+)\),$")
with open(lib9p_generated_c_fname, "r", encoding="utf-8") as fh:
for line in fh:
line = line.rstrip()
@@ -373,12 +380,9 @@ class Lib9PPlugin:
for c in chain[-self.CONFIG_9P_SRV_MAX_DEPTH :]
):
return True
- re_msg_meth = re.compile(
- r"^lib9p_(?P<grp>[TR])msg_(?P<meth>validate|unmarshal|marshal)$"
- )
- wrapper = next((c for c in chain if re_msg_meth.match(str(c))), None)
+ wrapper = next((c for c in chain if re_lib9p_caller.match(str(c))), None)
if wrapper:
- m = re_msg_meth.match(str(wrapper))
+ m = re_lib9p_caller.match(str(wrapper))
assert m
deny = m.group("meth") + "_" + ("R" if m.group("grp") == "T" else "T")
if str(call.base()).startswith(deny):
@@ -717,6 +721,15 @@ class PicoSDKPlugin:
return ret
+re_tud_class = re.compile(
+ r"^\s*#\s*define\s+(?P<k>CFG_TUD_(?:\S{3}|AUDIO|VIDEO|MIDI|VENDOR|USBTMC|DFU_RUNTIME|ECM_RNDIS))\s+(?P<v>\S+).*"
+)
+re_tud_entry = re.compile(r"^\s+\.(?P<meth>\S+)\s*=\s*(?P<impl>[a-zA-Z0-9_]+)(?:,.*)?")
+re_tud_if1 = re.compile(r"^\s*#\s*if (\S+)\s*")
+re_tud_if2 = re.compile(r"^\s*#\s*if (\S+)\s*\|\|\s*(\S+)\s*")
+re_tud_endif = re.compile(r"^\s*#\s*endif\s*")
+
+
class TinyUSBDevicePlugin:
tud_drivers: dict[str, set[QName]] # method_name => {method_impls}
@@ -734,9 +747,6 @@ class TinyUSBDevicePlugin:
return
assert tusb_config_h_fname
- re_tud_class = re.compile(
- r"^\s*#\s*define\s+(?P<k>CFG_TUD_(?:\S{3}|AUDIO|VIDEO|MIDI|VENDOR|USBTMC|DFU_RUNTIME|ECM_RNDIS))\s+(?P<v>\S+).*"
- )
tusb_config: dict[str, bool] = {}
with open(tusb_config_h_fname, "r", encoding="utf-8") as fh:
in_table = False
@@ -748,12 +758,6 @@ class TinyUSBDevicePlugin:
tusb_config[k] = bool(int(v))
tud_drivers: dict[str, set[QName]] = {}
- re_tud_entry = re.compile(
- r"^\s+\.(?P<meth>\S+)\s*=\s*(?P<impl>[a-zA-Z0-9_]+)(?:,.*)?"
- )
- re_tud_if1 = re.compile(r"^\s*#\s*if (\S+)\s*")
- re_tud_if2 = re.compile(r"^\s*#\s*if (\S+)\s*\|\|\s*(\S+)\s*")
- re_tud_endif = re.compile(r"^\s*#\s*endif\s*")
with open(usbd_c_fname, "r", encoding="utf-8") as fh:
in_table = False
enabled = True
diff --git a/build-aux/measurestack/util.py b/build-aux/measurestack/util.py
index e878ffa..5367da9 100644
--- a/build-aux/measurestack/util.py
+++ b/build-aux/measurestack/util.py
@@ -37,8 +37,10 @@ def synthetic_node(
return n
+re_location = re.compile(r"(?P<filename>.+):(?P<row>[0-9]+):(?P<col>[0-9]+)")
+
+
def read_source(location: str) -> str:
- re_location = re.compile(r"(?P<filename>.+):(?P<row>[0-9]+):(?P<col>[0-9]+)")
m = re_location.fullmatch(location)
if not m:
raise ValueError(f"unexpected label value {location!r}")
diff --git a/build-aux/measurestack/vcg.py b/build-aux/measurestack/vcg.py
index ca20b34..39755e9 100644
--- a/build-aux/measurestack/vcg.py
+++ b/build-aux/measurestack/vcg.py
@@ -26,16 +26,16 @@ class VCGElem:
attrs: dict[str, str]
+re_beg = re.compile(r"(edge|node):\s*\{\s*")
+_re_tok = r"[a-zA-Z_][a-zA-Z0-9_]*"
+_re_str = r'"(?:[^\"]|\\.)*"'
+re_attr = re.compile("(" + _re_tok + r")\s*:\s*(" + _re_tok + "|" + _re_str + r")\s*")
+re_end = re.compile(r"\}\s*$")
+re_skip = re.compile(r"(graph:\s*\{\s*title\s*:\s*" + _re_str + r"\s*|\})\s*")
+re_esc = re.compile(r"\\.")
+
+
def parse_vcg(reader: typing.TextIO) -> typing.Iterator[VCGElem]:
- re_beg = re.compile(r"(edge|node):\s*\{\s*")
- _re_tok = r"[a-zA-Z_][a-zA-Z0-9_]*"
- _re_str = r'"(?:[^\"]|\\.)*"'
- re_attr = re.compile(
- "(" + _re_tok + r")\s*:\s*(" + _re_tok + "|" + _re_str + r")\s*"
- )
- re_end = re.compile(r"\}\s*$")
- re_skip = re.compile(r"(graph:\s*\{\s*title\s*:\s*" + _re_str + r"\s*|\})\s*")
- re_esc = re.compile(r"\\.")
for lineno, line in enumerate(reader):
pos = 0