neuroflow-cpp / scripts /stub_evaluator.py
cwenzi's picture
Upload folder using huggingface_hub
26d5b81 verified
Raw
History Blame Contribute Delete
5.78 kB
import os
import re
import json
import argparse
import logging
logger = logging.getLogger(__name__)
HEADER_ONLY_PROS = [
"无需编译.cpp文件,包含即可用",
"模板代码可内联优化",
"分发简单(单头文件)",
"适合小型模板库",
"避免链接顺序问题",
]
HEADER_ONLY_CONS = [
"编译时间随包含次数线性增长",
"二进制体积膨胀(重复实例化)",
"循环依赖风险高",
"调试困难(模板展开复杂)",
"IDE代码补全和跳转受限",
"修改头文件触发全量重编译",
]
COMPILED_SEP_PROS = [
"编译时间可控(修改cpp仅重编译单文件)",
"二进制体积小(单次实例化)",
"可隐藏实现细节(Pimpl模式)",
"循环依赖易解(前向声明)",
"调试友好(独立编译单元)",
"增量编译高效",
]
COMPILED_SEP_CONS = [
"需维护hpp/cpp文件对",
"模板代码仍需在头文件",
"构建系统更复杂",
"分发需同时提供头文件和库文件",
"链接顺序可能出错",
]
def analyze_stub_file(file_path):
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
lines = f.readlines()
total = len(lines)
effective = sum(1 for l in lines if l.strip() and not l.strip().startswith("//"))
has_include = any("#include" in l for l in lines)
has_namespace = any("namespace" in l for l in lines)
has_impl = any(re.search(r'\w+::\w+', l) for l in lines if not l.strip().startswith("//"))
is_stub = effective <= 5 and not has_impl
return {
"path": file_path, "total_lines": total, "effective_lines": effective,
"is_stub": is_stub, "has_include": has_include, "has_namespace": has_namespace,
"has_implementation": has_impl,
}
def analyze_hpp_template_ratio(hpp_dir):
reports = {}
for fname in os.listdir(hpp_dir):
if not fname.endswith(".hpp"):
continue
fpath = os.path.join(hpp_dir, fname)
with open(fpath, "r", encoding="utf-8", errors="ignore") as f:
lines = f.readlines()
total = len(lines)
template_lines = sum(1 for l in lines if "template" in l)
reports[fname] = {"total_lines": total, "template_lines": template_lines,
"ratio": template_lines / total if total > 0 else 0}
return reports
def make_mode_decision(stub_reports, template_reports):
decision = {"mode": "MIXED", "details": []}
for fname, info in template_reports.items():
if info["ratio"] > 0.05:
decision["details"].append((fname, "HEADER_ONLY", "模板占比高,保持Header-Only"))
else:
decision["details"].append((fname, "COMPILED_SEP", "模板占比低,迁移到编译分离"))
return decision
def generate_cmake_patch(current_cmake_path):
patch_lines = [
"# === NeuroFlow 文件完整性补丁 ===",
"# 在neuroflow_core源文件列表中添加:",
"# src/weight_io.cpp",
"# 新增训练可执行目标:",
"# add_executable(neuroflow_train_v2 src/train_v2.cpp)",
"# target_link_libraries(neuroflow_train_v2 PRIVATE neuroflow_core OpenMP::OpenMP_CXX)",
]
return "\n".join(patch_lines)
def generate_evaluation_report(stub_reports, template_reports, decision, cmake_patch):
lines = ["# NeuroFlow 空壳源文件评估报告\n"]
lines.append("## 空壳文件分析\n")
for r in stub_reports:
status = "✅ 空壳" if r["is_stub"] else "❌ 非空壳"
lines.append(f"- `{r['path']}`: {r['total_lines']}行, 有效{r['effective_lines']}行, {status}")
lines.append("\n## Header-Only vs 编译分离\n")
lines.append("### Header-Only 优点\n")
for p in HEADER_ONLY_PROS:
lines.append(f"- {p}")
lines.append("\n### Header-Only 缺点\n")
for c in HEADER_ONLY_CONS:
lines.append(f"- {c}")
lines.append("\n### 编译分离 优点\n")
for p in COMPILED_SEP_PROS:
lines.append(f"- {p}")
lines.append("\n### 编译分离 缺点\n")
for c in COMPILED_SEP_CONS:
lines.append(f"- {c}")
lines.append(f"\n## 混合模式决策: **{decision['mode']}**\n")
for fname, mode, reason in decision["details"]:
lines.append(f"- `{fname}`: **{mode}** — {reason}")
lines.append("\n## CMakeLists.txt 修改方案\n")
lines.append(f"```cmake\n{cmake_patch}\n```")
return "\n".join(lines)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description="NeuroFlow空壳源文件评估器")
parser.add_argument("--source-dir", type=str, default="src", help="源文件目录")
parser.add_argument("--include-dir", type=str, default="include/neuroflow", help="头文件目录")
parser.add_argument("--cmake", type=str, default="CMakeLists.txt", help="CMakeLists.txt路径")
parser.add_argument("--output", type=str, default="report_stub_evaluation.md", help="输出报告路径")
args = parser.parse_args()
stub_reports = []
for f in os.listdir(args.source_dir):
if f.endswith(".cpp"):
stub_reports.append(analyze_stub_file(os.path.join(args.source_dir, f)))
template_reports = analyze_hpp_template_ratio(args.include_dir)
decision = make_mode_decision(stub_reports, template_reports)
cmake_patch = generate_cmake_patch(args.cmake)
report = generate_evaluation_report(stub_reports, template_reports, decision, cmake_patch)
with open(args.output, "w", encoding="utf-8") as f:
f.write(report)
logger.info(f"评估报告已保存到 {args.output}")