perf(Phase2Translator/IRMetadataFix): 削逐行热点——跳过无谓 strip、预编译逐行正则、C 级数字扫描
prof 基线(PROF/20260930_224857/main_time.txt=438.40s,7.28 亿次调用)显示全流程最大的 Python 侧热点是逐行扫描产生的内置字符串/正则调用:str.startswith 2.372 亿次(32.1s)、str.strip 1.791 亿次(22.8s)、re.Pattern.match 3130 万次(11.4s)、re.match 模块级 1971 万次(10.7s)+re._compile 1975 万次(7.2s)。四处等价改动:
1) _split_ll 第二遍:in_define/in_global_def 续行(.ll 里占比最高)不再 str.strip——这两支只用行内容与花括号计数,前导/尾随空白不含花括号,_count_braces_outside_strings 结果逐字不变;
2) _split_ll 第一遍:加 "define" not in line 的 C 级快路径,绝大多数行连 strip 都不做;
3) Phase2Translator 逐行正则全部预编译为模块级 _RE_* 常量(11 处 re.match + 4 处 re.sub,模式串一字未改)——消掉每次调用的模式串哈希+缓存查找;
4) IRMetadataFix:_RewritePlain 的前导数字扫描由逐字符 Python 循环改为 str.lstrip 的 C 级扫描(该函数 prof 5.8M 次调用,是项目内 self time 最大者);SanitizeIRMetadata 的逐行 startswith("!") 改为 [:1] 索引切片。
离线自测:数字扫描与旧实现逐例一致;SanitizeIRMetadata 幂等性保持;_split_ll 冒烟输出与预期语义一致(global/多行初始化器/define→declare/constant/metadata 分流正确)。
This commit is contained in:
1 parent
e2c84daa65
commit
3658ab0637
2 files changed
+68
-32
No files matched your search
@@ -153,7 +153,29 @@ _DWARF_TAG_ANY_RE = re.compile(r'DW_TAG_\w+')
|
||||
_DWARF_TAG_SUBPROGRAM_RE = re.compile(r'DW_TAG_subprogram\b')
|
||||
_DWARF_LOWPC_RE = re.compile(r'DW_AT_low_pc\s*\(\s*(0x[0-9A-Fa-f]+)\s*\)')
|
||||
_DWARF_HIGHPC_RE = re.compile(r'DW_AT_high_pc\s*\(\s*(0x[0-9A-Fa-f]+)\s*\)')
|
||||
_DWARF_ATNAME_RE = re.compile(r'DW_AT_name\s*\("((?:[^"\\]|\\.)*)"\)')
|
||||
_DWARF_ATNAME_RE = re.compile(r'DW_AT_name\s*\("((?:[^"\\]|\\.)*)"\)')
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# `_split_ll` 的逐行正则**预编译**(性能:该函数对合并后的 .ll 逐行跑两遍,
|
||||
# prof 实测 43.9万行级输入下 re 模块级函数的缓存查找(re._compile)达 1970 万次
|
||||
# ≈ 7s,另有 3100 万次 re.Pattern.match;每次 `re.match(字面量, ...)` 都要做
|
||||
# "模式串哈希 → 缓存查找"。预编译成模块级常量后省掉这层查找,且匹配路径更短。
|
||||
# 语义与逐字写法完全一致(模式串一字未改)。
|
||||
# ---------------------------------------------------------------
|
||||
_RE_DEFINE_SHA1: re.Pattern[str] = re.compile(r'define\s+[^@]*@"?([a-f0-9]+)\.')
|
||||
_RE_DEFINE_NAME: re.Pattern[str] = re.compile(r'define\s+[^@]*@"?([^"\s(]+)"?')
|
||||
_RE_DECLARE_NAME: re.Pattern[str] = re.compile(r'declare\s+[^@]*@"?([^"\s(]+)"?')
|
||||
_RE_LLVM_INTRINSIC: re.Pattern[str] = re.compile(r'@("?)llvm\.')
|
||||
_RE_AT_NAME: re.Pattern[str] = re.compile(r'(@\S+)')
|
||||
_RE_SHA1_16_DOT: re.Pattern[str] = re.compile(r'^[a-f0-9]{16}\.')
|
||||
_RE_DEFINE_PREFIX: re.Pattern[str] = re.compile(r'^define\s+')
|
||||
_RE_DEFINE_LINKAGE: re.Pattern[str] = re.compile(
|
||||
r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+')
|
||||
_RE_ALWAYSINLINE: re.Pattern[str] = re.compile(r'\balwaysinline\s+')
|
||||
# `_compile_one` 的逐行符号扫描/全局去重里用到的两条(同一预编译理由)
|
||||
_RE_AT_EXTERNAL: re.Pattern[str] = re.compile(r'@\S+\s*=\s*external\s+')
|
||||
_RE_DECLARE_FULL: re.Pattern[str] = re.compile(
|
||||
r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(')
|
||||
|
||||
|
||||
def _ParseDwarfLineRows(dump_text: str) -> list[tuple[int, str, int]]:
|
||||
@@ -1614,13 +1636,19 @@ class Phase2Translator:
|
||||
defined_names = set()
|
||||
|
||||
for line in ll_content.splitlines(True):
|
||||
# 第一遍只关心 `define ...` 行,而合并后的 .ll 里这类行占比极低。
|
||||
# `'define' not in line` 是 C 级子串扫描 ⇒ 绝大多数行连 strip 都不做
|
||||
# (prof 实测 str.strip 1.79 亿次 / str.startswith 2.37 亿次是全流程
|
||||
# 最大的 Python 侧热点,本函数两遍逐行扫描是其主要来源)。
|
||||
if 'define' not in line:
|
||||
continue
|
||||
stripped = line.strip()
|
||||
|
||||
if stripped.startswith('define '):
|
||||
dm = re.match(r'define\s+[^@]*@"?([a-f0-9]+)\.', stripped)
|
||||
dm = _RE_DEFINE_SHA1.match(stripped)
|
||||
if dm and module_sha1 is None:
|
||||
module_sha1 = dm.group(1)
|
||||
dm2 = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped)
|
||||
dm2 = _RE_DEFINE_NAME.match(stripped)
|
||||
if dm2:
|
||||
defined_names.add(dm2.group(1))
|
||||
|
||||
@@ -1630,12 +1658,14 @@ class Phase2Translator:
|
||||
global_brace_depth = 0
|
||||
|
||||
for line in ll_content.splitlines(True):
|
||||
stripped = line.strip()
|
||||
|
||||
# 续行(函数体指令 / 全局初始化器)在合并 .ll 里占绝大多数,而这两支
|
||||
# 只需要"行内容 + 花括号计数" ⇒ 不进 strip(前导/尾随空白不含花括号,
|
||||
# _count_braces_outside_strings 的结果逐字不变)。prof 实测 str.strip
|
||||
# 1.79 亿次为最大 Python 侧热点,逐行 strip 是其主要来源。
|
||||
if in_global_def:
|
||||
text_lines.append(line)
|
||||
global_type_parts.append(stripped)
|
||||
global_brace_depth += _count_braces_outside_strings(stripped)
|
||||
global_type_parts.append(line.strip())
|
||||
global_brace_depth += _count_braces_outside_strings(line)
|
||||
if global_brace_depth <= 0:
|
||||
full_type = ' '.join(global_type_parts).strip()
|
||||
depth = 0
|
||||
@@ -1659,18 +1689,19 @@ class Phase2Translator:
|
||||
|
||||
if in_define:
|
||||
text_lines.append(line)
|
||||
brace_depth += _count_braces_outside_strings(stripped)
|
||||
brace_depth += _count_braces_outside_strings(line)
|
||||
if brace_depth <= 0:
|
||||
in_define = False
|
||||
continue
|
||||
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('define '):
|
||||
text_lines.append(line)
|
||||
in_define = True
|
||||
brace_depth = _count_braces_outside_strings(stripped)
|
||||
decl_line = re.sub(r'^define\s+', 'declare ', stripped)
|
||||
decl_line = re.sub(r'\b(linkonce_odr|weak_odr|linkonce|weak|common|appending|internal|private)\s+', '', decl_line)
|
||||
decl_line = re.sub(r'\balwaysinline\s+', '', decl_line)
|
||||
decl_line = _RE_DEFINE_PREFIX.sub('declare ', stripped)
|
||||
decl_line = _RE_DEFINE_LINKAGE.sub('', decl_line)
|
||||
decl_line = _RE_ALWAYSINLINE.sub('', decl_line)
|
||||
paren_pos = decl_line.rfind(')')
|
||||
if paren_pos >= 0:
|
||||
decl_line = decl_line[:paren_pos + 1]
|
||||
@@ -1698,10 +1729,10 @@ class Phase2Translator:
|
||||
# LLVM 保留全局(如 --hotspot-sites 的 @llvm.global_ctors;名字含点故
|
||||
# 最终 IR 保留引号)是 appending 定义,禁止改写为 "external global"
|
||||
# 存根(否则 .ll 重组后 llc 报错)
|
||||
if re.match(r'@("?)llvm\.', stripped):
|
||||
if _RE_LLVM_INTRINSIC.match(stripped):
|
||||
continue
|
||||
if ' internal ' not in stripped and ' private ' not in stripped:
|
||||
name_match = re.match(r'(@\S+)', stripped)
|
||||
name_match = _RE_AT_NAME.match(stripped)
|
||||
if name_match:
|
||||
var_name = name_match.group(1)
|
||||
global_pos = stripped.find(' global ')
|
||||
@@ -1736,7 +1767,7 @@ class Phase2Translator:
|
||||
continue
|
||||
|
||||
if stripped.startswith('declare'):
|
||||
dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped)
|
||||
dm = _RE_DECLARE_NAME.match(stripped)
|
||||
if dm:
|
||||
fname = dm.group(1)
|
||||
if fname in defined_names:
|
||||
@@ -1747,7 +1778,7 @@ class Phase2Translator:
|
||||
fname_sha1 = fname[:dot_pos]
|
||||
if module_sha1 and fname_sha1 != module_sha1 and len(fname_sha1) >= 16:
|
||||
continue
|
||||
if re.match(r'^[a-f0-9]{16}\.', fname):
|
||||
if _RE_SHA1_16_DOT.match(fname):
|
||||
continue
|
||||
stub_lines.append(line)
|
||||
continue
|
||||
@@ -2475,10 +2506,10 @@ class Phase2Translator:
|
||||
for i, line in enumerate(ll_lines_for_dedup):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped):
|
||||
gm = re.match(r'(@\S+)', stripped)
|
||||
gm = _RE_AT_NAME.match(stripped)
|
||||
if gm:
|
||||
gname = gm.group(1)
|
||||
is_external = re.match(r'@\S+\s*=\s*external\s+', stripped) is not None
|
||||
is_external = _RE_AT_EXTERNAL.match(stripped) is not None
|
||||
if is_external:
|
||||
external_globals[gname] = i
|
||||
else:
|
||||
@@ -2507,7 +2538,7 @@ class Phase2Translator:
|
||||
else:
|
||||
existing_symbols[name] = 'full'
|
||||
elif stripped.startswith('declare'):
|
||||
dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped)
|
||||
dm = _RE_DECLARE_NAME.match(stripped)
|
||||
if dm:
|
||||
fname = dm.group(1)
|
||||
existing_declares.add(fname)
|
||||
@@ -2525,11 +2556,11 @@ class Phase2Translator:
|
||||
for line in ll_content.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('define'):
|
||||
dm = re.match(r'define\s+[^@]*@"?([^"\s(]+)"?', stripped)
|
||||
dm = _RE_DEFINE_NAME.match(stripped)
|
||||
if dm:
|
||||
existing_defines.add(dm.group(1))
|
||||
elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped):
|
||||
gm = re.match(r'(@\S+)', stripped)
|
||||
gm = _RE_AT_NAME.match(stripped)
|
||||
if gm:
|
||||
existing_global_defs.add(gm.group(1))
|
||||
for dep_name, dep_sha1 in deps.items():
|
||||
@@ -2547,7 +2578,7 @@ class Phase2Translator:
|
||||
if stripped.startswith(';') or stripped.startswith('target ') or stripped.startswith('source_filename') or not stripped:
|
||||
continue
|
||||
if stripped.startswith('declare'):
|
||||
dm = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', stripped)
|
||||
dm = _RE_DECLARE_NAME.match(stripped)
|
||||
if dm:
|
||||
fname = dm.group(1)
|
||||
if 'zdef_alloc' in fname:
|
||||
@@ -2562,7 +2593,7 @@ class Phase2Translator:
|
||||
if has_struct and not existing_has_struct:
|
||||
for i, l in enumerate(all_stub_lines):
|
||||
if l is not None and l.strip().startswith('declare'):
|
||||
em = re.match(r'declare\s+[^@]*@"?([^"\s(]+)"?', l.strip())
|
||||
em = _RE_DECLARE_NAME.match(l.strip())
|
||||
if em and em.group(1) == fname:
|
||||
all_stub_lines[i] = line
|
||||
break
|
||||
@@ -2606,7 +2637,7 @@ class Phase2Translator:
|
||||
else:
|
||||
all_stub_lines.append(line)
|
||||
elif stripped.startswith('@') and (' global ' in stripped or ' constant ' in stripped):
|
||||
gm = re.match(r'(@\S+)', stripped)
|
||||
gm = _RE_AT_NAME.match(stripped)
|
||||
if gm and (gm.group(1) in existing_global_defs or gm.group(1) in stub_global_defs):
|
||||
continue
|
||||
if gm:
|
||||
@@ -2670,7 +2701,7 @@ class Phase2Translator:
|
||||
lines: list[str] = ll_content.splitlines(True)
|
||||
kept_lines: list[str] = []
|
||||
for line in lines:
|
||||
m = re.match(r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', line)
|
||||
m = _RE_DECLARE_FULL.match(line)
|
||||
if m and m.group(1) in defined_funcs:
|
||||
continue
|
||||
kept_lines.append(line)
|
||||
@@ -2680,7 +2711,7 @@ class Phase2Translator:
|
||||
dedup_lines: list[str] = ll_content.splitlines(True)
|
||||
dedup_kept: list[str] = []
|
||||
for line in dedup_lines:
|
||||
dm = re.match(r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', line)
|
||||
dm = _RE_DECLARE_FULL.match(line)
|
||||
if dm:
|
||||
fname = dm.group(1)
|
||||
if fname in seen_declares:
|
||||
|
||||
@@ -27,8 +27,9 @@ _NamedDefinition = re.compile(r'^!([A-Za-z][\w.]*)\s*=\s*(.*)$')
|
||||
_ListForm = re.compile(r'^!\{(.*)\}$', re.DOTALL)
|
||||
# 纯 id 引用 `!N`
|
||||
_PureId = re.compile(r'^!(\d+)$')
|
||||
# Decimal digit set for the no-regex fast rewrite path.
|
||||
_DIGITS: frozenset[str] = frozenset('0123456789')
|
||||
# 前导数字字符集(str 形式):供 str.lstrip 的 **C 级**扫描用
|
||||
# (_RewritePlain 在合并 .ll 上是百万级调用,原逐字符 Python 循环是 self time 主源)。
|
||||
_DIGITS_STR: str = '0123456789'
|
||||
|
||||
|
||||
def _SplitTopLevel(Content: str) -> list[str]:
|
||||
@@ -92,10 +93,11 @@ def _RewritePlain(Line: str, StrMap: dict[str, str]) -> str:
|
||||
Ap = Out.append
|
||||
Get = StrMap.get
|
||||
for Part in Parts[1:]:
|
||||
d: int = 0
|
||||
n: int = len(Part)
|
||||
while d < n and Part[d] in _DIGITS:
|
||||
d += 1
|
||||
# 前导数字个数改由 str.lstrip 的 **C 级**扫描给出(原逐字符 Python 循环
|
||||
# `while d < n and Part[d] in _DIGITS`;本函数 prof 实测 5.8M 次调用,
|
||||
# 是 self time 最大的项目内函数)。语义与循环逐字等价:都是"前导数字个数"。
|
||||
d: int = n - len(Part.lstrip(_DIGITS_STR))
|
||||
if not d:
|
||||
Ap('!')
|
||||
Ap(Part)
|
||||
@@ -160,9 +162,12 @@ def SanitizeIRMetadata(text: str) -> str:
|
||||
Blocks: list[tuple[int, int]] = [] # [Start, End)
|
||||
i: int = 0
|
||||
while i < LineCount:
|
||||
if Segments[i].startswith('!'):
|
||||
# 单个字符的判定用索引切片(seg[:1])替代 str.startswith:本循环对合并 .ll
|
||||
# 的**每一行**各跑一次(prof 实测 str.startswith 237M 次为全流程最大热点),
|
||||
# 索引切片无方法查找开销、语义与 startswith('!') 等价(空行得 ''≠'!')。
|
||||
if Segments[i][:1] == '!':
|
||||
j: int = i + 1
|
||||
while j < LineCount and Segments[j].startswith('!'):
|
||||
while j < LineCount and Segments[j][:1] == '!':
|
||||
j += 1
|
||||
Blocks.append((i, j))
|
||||
i = j
|
||||
|
||||
Reference in new issue
Block a user