Skip to content

Commit 248a735

Browse files
Merge pull request #413 from HecreReed/codex/issue380-release-coldstart
fix(mac): reduce ptoas cold-start in release dist
2 parents 67311fc + 3033180 commit 248a735

2 files changed

Lines changed: 136 additions & 30 deletions

File tree

docker/collect_ptoas_dist_mac.sh

Lines changed: 124 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ if [ ! -f "$PTOAS_BIN" ]; then
4848
exit 1
4949
fi
5050

51+
detect_ptoas_version() {
52+
local cache_file="${PTO_SOURCE_DIR}/build/CMakeCache.txt"
53+
local version=""
54+
if [[ -f "${cache_file}" ]]; then
55+
version="$(awk -F= '/^PTOAS_RELEASE_VERSION_OVERRIDE:STRING=/{print $2}' "${cache_file}")"
56+
if [[ -z "${version}" ]]; then
57+
version="$(awk -F= '/^CMAKE_PROJECT_VERSION:STATIC=/{print $2}' "${cache_file}")"
58+
fi
59+
fi
60+
printf '%s' "${version}"
61+
}
62+
63+
PTOAS_WRAPPER_VERSION="$(detect_ptoas_version)"
64+
5165
mkdir -p "${PTOAS_DIST_DIR}/bin" "${PTOAS_DEPS_DIR}"
5266
cp -fL "$PTOAS_BIN" "${PTOAS_DIST_DIR}/bin/"
5367
chmod +x "${PTOAS_DIST_DIR}/bin/ptoas"
@@ -233,12 +247,110 @@ for target in iter_targets():
233247
PY
234248
}
235249

250+
strip_nonportable_rpaths() {
251+
python3 - "${PTOAS_DIST_DIR}" <<'PY'
252+
import os
253+
import subprocess
254+
import sys
255+
from pathlib import Path
256+
257+
root = Path(sys.argv[1]).resolve()
258+
allowed_prefixes = (
259+
"@loader_path/",
260+
"@executable_path/",
261+
)
262+
263+
264+
def iter_targets():
265+
for base, _, files in os.walk(root):
266+
for name in sorted(files):
267+
if name == "ptoas" or name.endswith(".dylib"):
268+
yield Path(base, name).resolve()
269+
270+
271+
def iter_rpaths(target: Path):
272+
output = subprocess.check_output(
273+
["otool", "-l", str(target)],
274+
stderr=subprocess.STDOUT,
275+
text=True,
276+
)
277+
want = False
278+
for line in output.splitlines():
279+
fields = line.strip().split()
280+
if len(fields) >= 2 and fields[0] == "cmd" and fields[1] == "LC_RPATH":
281+
want = True
282+
continue
283+
if want and len(fields) >= 2 and fields[0] == "path":
284+
yield fields[1]
285+
want = False
286+
287+
288+
for target in iter_targets():
289+
for rpath in list(iter_rpaths(target)):
290+
if rpath.startswith(allowed_prefixes):
291+
continue
292+
print(f"delete non-portable rpath: {target} :: {rpath}")
293+
subprocess.check_call(
294+
["install_name_tool", "-delete_rpath", rpath, str(target)]
295+
)
296+
PY
297+
}
298+
299+
validate_packaged_ptoas_surface() {
300+
python3 - "${PTOAS_DIST_DIR}/bin/ptoas" <<'PY'
301+
import fnmatch
302+
import os
303+
import subprocess
304+
import sys
305+
from pathlib import Path
306+
307+
target = Path(sys.argv[1]).resolve()
308+
denylist = (
309+
"libMLIRMlirOptMain.dylib",
310+
"libMLIROptLib.dylib",
311+
"libMLIR*Test*.dylib",
312+
"libMLIR*TestPasses*.dylib",
313+
)
314+
315+
output = subprocess.check_output(
316+
["otool", "-L", str(target)],
317+
stderr=subprocess.STDOUT,
318+
text=True,
319+
)
320+
deps = []
321+
for line in output.splitlines()[1:]:
322+
dep = line.strip().split(" ", 1)[0]
323+
if dep:
324+
deps.append(os.path.basename(dep))
325+
326+
bad = sorted(
327+
{
328+
dep
329+
for dep in deps
330+
if any(fnmatch.fnmatch(dep, pattern) for pattern in denylist)
331+
}
332+
)
333+
if bad:
334+
for dep in bad:
335+
print(
336+
f"ERROR: packaged ptoas still links forbidden cold-start dependency: {dep}",
337+
file=sys.stderr,
338+
)
339+
sys.exit(1)
340+
341+
print(f"ptoas direct dylib dependency count: {len(deps)}")
342+
PY
343+
}
344+
236345
echo "Collecting dylib dependencies..."
237346
collect_dylibs "${PTOAS_DIST_DIR}/bin/ptoas"
238347

239348
echo "Rewriting packaged install names..."
240349
rewrite_packaged_install_names
241350

351+
echo "Stripping non-portable rpaths..."
352+
strip_nonportable_rpaths
353+
242354
echo "Validating packaged dependency install names..."
243355
if ! python3 - "${PTOAS_DIST_DIR}" <<'PY'
244356
import os
@@ -288,6 +400,9 @@ then
288400
exit 1
289401
fi
290402

403+
echo "Validating packaged ptoas dependency surface..."
404+
validate_packaged_ptoas_surface
405+
291406
if ! command -v codesign >/dev/null 2>&1; then
292407
echo "Error: codesign is required on macOS to sign packaged artifacts" >&2
293408
exit 1
@@ -307,16 +422,20 @@ done
307422
shopt -u nullglob
308423

309424
echo "Creating wrapper script..."
310-
cat > "${PTOAS_DIST_DIR}/ptoas" << 'WRAPPER_EOF'
425+
cat > "${PTOAS_DIST_DIR}/ptoas" <<WRAPPER_EOF
311426
#!/bin/bash
312-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
313-
export DYLD_LIBRARY_PATH="${SCRIPT_DIR}/lib:${DYLD_LIBRARY_PATH}"
314-
exec "${SCRIPT_DIR}/bin/ptoas" "$@"
427+
SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
428+
if [[ \$# -eq 1 && "\${1:-}" == "--version" && -n "${PTOAS_WRAPPER_VERSION}" ]]; then
429+
printf 'ptoas %s\n' "${PTOAS_WRAPPER_VERSION}"
430+
exit 0
431+
fi
432+
export DYLD_LIBRARY_PATH="\${SCRIPT_DIR}/lib:\${DYLD_LIBRARY_PATH}"
433+
exec "\${SCRIPT_DIR}/bin/ptoas" "\$@"
315434
WRAPPER_EOF
316435
chmod +x "${PTOAS_DIST_DIR}/ptoas"
317436

318437
echo "Smoke testing packaged ptoas dist..."
319-
env -u DYLD_LIBRARY_PATH -u LD_LIBRARY_PATH "${PTOAS_DIST_DIR}/ptoas" --version
438+
env -u DYLD_LIBRARY_PATH -u LD_LIBRARY_PATH "${PTOAS_DIST_DIR}/bin/ptoas" --version >/dev/null
320439
env -u DYLD_LIBRARY_PATH -u LD_LIBRARY_PATH \
321440
"${PTOAS_DIST_DIR}/ptoas" \
322441
"${PTO_SOURCE_DIR}/test/basic/kernel_kind_vector_scf_while_emitc.pto" \

tools/ptoas/CMakeLists.txt

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,24 @@
66
# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
77
# See LICENSE in the root of the software repository for the full text of the License.
88

9-
# Please refer to the License for details. You may not use this file except in compliance with the License.
10-
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
11-
# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
12-
# See LICENSE in the root of the software repository for the full text of the License.
13-
149
set(LLVM_LINK_COMPONENTS
1510
Support
1611
Core
1712
)
1813

19-
# [修改 1] 重命名目标: ptoas -> pto-opt
20-
# 原因:LLVM 构建目录里已经有一个 ptoas 了,重名会导致 CMake 报错。
2114
add_llvm_executable(pto-opt
2215
ptoas.cpp
2316
)
24-
# =========================================================
25-
# [新增] 魔法操作:修改最终输出的文件名为 "ptoas"
26-
# =========================================================
17+
2718
set_target_properties(pto-opt PROPERTIES OUTPUT_NAME "ptoas")
2819
target_compile_definitions(pto-opt PRIVATE
2920
PTOAS_RELEASE_VERSION="${PTOAS_CLI_VERSION}"
3021
)
31-
# [修改 2] 更新链接库名称
32-
# 原因:In-tree 时你的库叫 MLIRPTODialect,但现在 Out-of-tree 它们是你自己定义的
33-
# (通常在 lib/PTO/IR/CMakeLists.txt 里被定义为 PTOIR 或类似名字)。
22+
3423
target_link_libraries(pto-opt PRIVATE
35-
# === 你的本地库 (请确认 lib/PTO/*/CMakeLists.txt 里的定义名) ===
36-
PTOIR # 替代 MLIRPTODialect
37-
PTOTransforms # 替代 MLIRPTOTransforms
24+
PTOIR
25+
PTOTransforms
3826
ptobc_lib
39-
40-
# === MLIR 基础设施 ===
41-
MLIRMlirOptMain # [重要] 包含了 main 函数入口逻辑,通常必须链接
42-
43-
# === MLIR 标准库 ===
4427
MLIRBufferizationTransforms
4528
MLIRArithTransforms
4629
MLIRTensorTransforms
@@ -49,7 +32,10 @@ target_link_libraries(pto-opt PRIVATE
4932
MLIRParser
5033
MLIRPass
5134
MLIREmitCDialect
35+
MLIREmitCTransforms
5236
MLIRSCFDialect
37+
MLIRSCFToControlFlow
38+
MLIRSCFTransforms
5339
MLIRGPUDialect
5440
MLIRTransforms
5541
MLIRTargetCpp
@@ -63,9 +49,10 @@ target_link_libraries(pto-opt PRIVATE
6349
MLIRTransformUtils
6450
)
6551

66-
# [修改 3] 更新依赖
67-
# 确保在编译 pto-opt 之前,TableGen 已经生成了头文件
68-
# "PTOOpsIncGen" 这个名字必须和你 include/PTO/IR/CMakeLists.txt 里定义的 add_public_tablegen_target 一致
52+
if(APPLE)
53+
target_link_options(pto-opt PRIVATE "-Wl,-dead_strip_dylibs")
54+
endif()
55+
6956
add_dependencies(pto-opt
70-
PTOOpsIncGen
57+
PTOOpsIncGen
7158
)

0 commit comments

Comments
 (0)