feat: 多轮运行 + GCOV 合并 + JSON 出力 + DesignDataGenerator
This commit is contained in:
+101
-53
@@ -351,9 +351,16 @@ def run_all(program_name: str, outdir: str, temp_dir: str,
|
||||
expected_records: list[dict] | None = None,
|
||||
source_dir: str | None = None,
|
||||
path_infos: list | None = None,
|
||||
multi_write_fds: set | None = None
|
||||
) -> list[GroupResult]:
|
||||
"""完整编排:编译 → 准备目录 → 逐组执行 → 出力保存。"""
|
||||
multi_write_fds: set | None = None,
|
||||
skip_records: list[dict] | None = None,
|
||||
skip_term_types: list[str] | None = None
|
||||
) -> tuple[list[GroupResult], dict[int, int] | None]:
|
||||
"""完整编排:编译 → 准备目录 → 逐组执行 → 出力保存。
|
||||
|
||||
Returns:
|
||||
(results_list, merged_gcov_data)
|
||||
merged_gcov_data is None when no gcov runs.
|
||||
"""
|
||||
source_dir = source_dir or str(Path(outdir).parent)
|
||||
work_dir = Path(temp_dir)
|
||||
work_dir.mkdir(parents=True, exist_ok=True)
|
||||
@@ -362,6 +369,11 @@ def run_all(program_name: str, outdir: str, temp_dir: str,
|
||||
multi_write_fds = multi_write_fds or set()
|
||||
|
||||
fd_field_dicts = _build_fd_field_dicts(fd_fields, fields_dict)
|
||||
assign_names = _input_assign_names(select_info, open_dir, fd_fields)
|
||||
|
||||
def _is_output_fd(fd_name: str) -> bool:
|
||||
dir_val = open_dir.get(fd_name, '')
|
||||
return dir_val in ('OUTPUT', 'I-O')
|
||||
|
||||
# ── 1. SUB 编译(V3)──
|
||||
sub_dir = _resolve_sub_dir(source_dir)
|
||||
@@ -373,63 +385,99 @@ def run_all(program_name: str, outdir: str, temp_dir: str,
|
||||
program_name, source_dir, str(work_dir), sub_o, cpy_dir
|
||||
)
|
||||
|
||||
# ── 3. 入力ファイル配置(V3)──
|
||||
input_dir = Path(outdir) / 'input'
|
||||
assign_names = _input_assign_names(select_info, open_dir, fd_fields)
|
||||
if input_dir.is_dir():
|
||||
for assign in assign_names:
|
||||
src = input_dir / assign
|
||||
if src.exists():
|
||||
shutil.copy2(str(src), str(work_dir / assign))
|
||||
logger.info(f" INPUT: {assign} ({src.stat().st_size} bytes)")
|
||||
# ── 3. 场景定义 ──
|
||||
scenes = [("main", records, term_types, expected,
|
||||
Path(outdir) / 'input', Path(outdir) / 'output')]
|
||||
if skip_records:
|
||||
skip_expected = [{}] * len(skip_records)
|
||||
skip_term = skip_term_types or ['normal'] * len(skip_records)
|
||||
scenes.append(("skip", skip_records, skip_term, skip_expected,
|
||||
Path(outdir) / 'input_skip', Path(outdir) / 'run_skip' / 'output'))
|
||||
|
||||
# ── 4. 清理旧 gcda + 执行 ──
|
||||
_clean_gcda(str(work_dir))
|
||||
results = []
|
||||
gcov_data_sets = []
|
||||
gcov_root = work_dir / "gcov"
|
||||
|
||||
def _is_output_fd(fd_name: str) -> bool:
|
||||
dir_val = open_dir.get(fd_name, '')
|
||||
return dir_val in ('OUTPUT', 'I-O')
|
||||
for scene_id, scene_recs, scene_terms, scene_expected, src_in_dir, dst_out_dir in scenes:
|
||||
# ── 3a. 入力ファイル配置 ──
|
||||
if src_in_dir.is_dir():
|
||||
for assign in assign_names:
|
||||
src = src_in_dir / assign
|
||||
if src.exists():
|
||||
shutil.copy2(str(src), str(work_dir / assign))
|
||||
|
||||
# output_input_files 只写入非 abend 记录,同步过滤 expected
|
||||
filtered_expected = []
|
||||
for i, rec in enumerate(expected):
|
||||
term = term_types[i] if i < len(term_types) else 'normal'
|
||||
if term != 'abend':
|
||||
filtered_expected.append(rec)
|
||||
expected = filtered_expected
|
||||
# ── 3b. 清理旧 gcda ──
|
||||
_clean_gcda(str(work_dir))
|
||||
|
||||
group = GroupInfo(
|
||||
name=program_name,
|
||||
records=records,
|
||||
expected_outputs=expected,
|
||||
expected_returncode=0,
|
||||
fd_field_dicts=fd_field_dicts,
|
||||
open_dir=open_dir,
|
||||
select_info=select_info,
|
||||
multi_write_fds=multi_write_fds,
|
||||
)
|
||||
# ── 3c. 过滤 non-abend ──
|
||||
filtered_exp = []
|
||||
for i, rec in enumerate(scene_expected):
|
||||
term = scene_terms[i] if i < len(scene_terms) else 'normal'
|
||||
if term != 'abend':
|
||||
filtered_exp.append(rec)
|
||||
|
||||
r = run_group(group, exe_path, str(work_dir))
|
||||
results = [r]
|
||||
group = GroupInfo(
|
||||
name=f"{program_name}_{scene_id}",
|
||||
records=scene_recs,
|
||||
expected_outputs=filtered_exp,
|
||||
expected_returncode=0,
|
||||
fd_field_dicts=fd_field_dicts,
|
||||
open_dir=open_dir,
|
||||
select_info=select_info,
|
||||
multi_write_fds=multi_write_fds,
|
||||
)
|
||||
|
||||
# 出力拷贝到 output_dir
|
||||
output_dir = Path(outdir) / 'output'
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
for fd_name in fd_field_dicts:
|
||||
if not _is_output_fd(fd_name):
|
||||
continue
|
||||
sel = select_info.get(fd_name, {})
|
||||
assign = sel.get('assign', fd_name) if isinstance(sel, dict) else fd_name
|
||||
src = os.path.join(str(work_dir), assign)
|
||||
dst = output_dir / assign
|
||||
if os.path.exists(src):
|
||||
shutil.copy2(src, str(dst))
|
||||
# ── 3d. 执行 ──
|
||||
r = run_group(group, exe_path, str(work_dir))
|
||||
results.append(r)
|
||||
|
||||
status = '✓' if r.passed else '✗'
|
||||
logger.info(f" 组 '{group.name}': returncode={r.returncode}, "
|
||||
f"{len(r.details)} fields, {status}")
|
||||
logger.info(f" EXIT={r.returncode}, 出力パス={work_dir}")
|
||||
return results
|
||||
status = '✓' if r.passed else '✗'
|
||||
logger.info(f" 组 '{group.name}': returncode={r.returncode}, {status}")
|
||||
|
||||
# ── 3e. 出力保存 ──
|
||||
dst_out_dir.mkdir(parents=True, exist_ok=True)
|
||||
for fd_name in fd_field_dicts:
|
||||
if not _is_output_fd(fd_name):
|
||||
continue
|
||||
sel = select_info.get(fd_name, {})
|
||||
assign = sel.get('assign', fd_name) if isinstance(sel, dict) else fd_name
|
||||
src = os.path.join(str(work_dir), assign)
|
||||
if os.path.exists(src):
|
||||
shutil.copy2(src, str(dst_out_dir / assign))
|
||||
|
||||
# ── 3f. .gcda 隔离(.gcno 是共享的,COPY;.gcda 是每场景独立的,MOVE)
|
||||
scene_gcov_dir = gcov_root / f"run_{scene_id}"
|
||||
scene_gcov_dir.mkdir(parents=True, exist_ok=True)
|
||||
for f in work_dir.glob("*.gcda"):
|
||||
if f.is_file() and f.stat().st_size > 0:
|
||||
dst = scene_gcov_dir / f.name
|
||||
if dst.exists():
|
||||
dst.unlink()
|
||||
shutil.move(str(f), str(dst))
|
||||
for f in work_dir.glob("*.gcno"):
|
||||
if f.is_file() and f.stat().st_size > 0:
|
||||
dst = scene_gcov_dir / f.name
|
||||
if not dst.exists():
|
||||
shutil.copy2(str(f), str(dst))
|
||||
|
||||
# ── 3g. 收集该场景的 gcov 数据 ──
|
||||
from .gcov import run_gcov as _run_gcov
|
||||
scene_data = _run_gcov(program_name, str(scene_gcov_dir))
|
||||
if scene_data:
|
||||
gcov_data_sets.append(scene_data)
|
||||
|
||||
logger.info(f" {scene_id} 完了, output={dst_out_dir}")
|
||||
|
||||
# ── 4. 合并 gcov ──
|
||||
merged_gcov = None
|
||||
if gcov_data_sets:
|
||||
merged_gcov = {}
|
||||
for ds in gcov_data_sets:
|
||||
for line, count in ds.items():
|
||||
merged_gcov[line] = max(merged_gcov.get(line, 0), count)
|
||||
logger.info(f" Merged gcov from {len(gcov_data_sets)} runs ({len(merged_gcov)} lines)")
|
||||
|
||||
return results, merged_gcov
|
||||
|
||||
|
||||
# ── run_and_compare(被 --run 调用,SOURCE 兼容)──
|
||||
|
||||
Reference in New Issue
Block a user