"""Single-API consistent pipeline driver (full workflow, no historical cpp reuse).
Steps: 03/04/05/06/07 yaml -> tiling coverage -> fuzz config -> normal cpp
-> compile -> normal precheck(1000, >=95%) -> deterministic check
-> consistent cpp -> verify V1-V10 -> compile(TARGET=consistent)
-> consistent precheck -> full consistent run -> parse report.
Status written into output/pipeline_status.json.
"""
import argparse
import json
import os
import re
import subprocess
import sys
import time
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUT = os.path.join(BASE, 'output')
FRAME = os.path.join(BASE, 'turing_sec', 'aclnnAPI_fuzz')
PLOG_DIR = os.environ.get('ASCEND_LOG_PATH', '/root/ascend/log/debug/plog')
STATUS_FILE = os.path.join(OUT, 'pipeline_status.json')
ENV = dict(os.environ)
ENV['ASCEND_HOME_PATH'] = ENV.get('ASCEND_HOME_PATH', '/usr/local/Ascend/ascend-toolkit/latest/x86_64-linux')
ENV['ASCEND_OPP_PATH'] = ENV.get('ASCEND_OPP_PATH', '/usr/local/Ascend/ascend-toolkit/latest/opp')
ENV['LD_LIBRARY_PATH'] = ENV['ASCEND_HOME_PATH'] + '/lib64:' + ENV.get('LD_LIBRARY_PATH', '')
def run(cmd, timeout=600, cwd=BASE, log_file=None):
p = subprocess.run(cmd, shell=True, cwd=cwd, capture_output=True, text=True, timeout=timeout, env=ENV)
if log_file:
with open(log_file, 'a', encoding='utf-8') as f:
f.write(f'\n===== CMD: {cmd}\n{p.stdout}\n{p.stderr}\n')
return p.returncode, p.stdout + p.stderr
def load_status():
if os.path.exists(STATUS_FILE):
with open(STATUS_FILE, encoding='utf-8') as f:
return json.load(f)
return {}
def save_status(st):
with open(STATUS_FILE, 'w', encoding='utf-8') as f:
json.dump(st, f, ensure_ascii=False, indent=1)
def count_success(log_path):
"""统计 FUZZ_RESULT success/faild 数量"""
s, d = 0, 0
if not os.path.exists(log_path):
return 0, 0
with open(log_path, encoding='utf-8', errors='ignore') as f:
for line in f:
if '[FUZZ_RESULT]' in line:
if ' success' in line:
s += 1
elif ' faild' in line:
d += 1
return s, d
def consistent_stats(log_path):
s, m, e = 0, 0, 0
if not os.path.exists(log_path):
return 0, 0, 0
with open(log_path, encoding='utf-8', errors='ignore') as f:
for line in f:
if '[FUZZ_CONSISTENT]' in line:
if 'type=consistent' in line and 'success' in line:
s += 1
elif 'hash_mismatch' in line:
m += 1
elif 'execute_error' in line:
e += 1
return s, m, e
def clear_plog():
subprocess.run(f'rm -f {PLOG_DIR}/plog-*.log', shell=True)
def pipeline(api, status):
t0 = time.time()
rec = {'status': 'RUNNING', 'start': time.strftime('%F %T')}
status[api] = rec
save_status(status)
tdir = os.path.join(OUT, api, 'test-design')
fdir = os.path.join(OUT, api, 'fuzz_logs')
os.makedirs(tdir, exist_ok=True)
os.makedirs(fdir, exist_ok=True)
drv_log = os.path.join(fdir, 'pipeline_driver.log')
def finish(st, detail=''):
rec['status'] = st
rec['detail'] = detail
rec['end'] = time.strftime('%F %T')
rec['minutes'] = round((time.time() - t0) / 60, 1)
save_status(status)
print(f'[{api}] {st} {detail} ({rec["minutes"]}min)')
rc, out = run(f'python scripts/auto_gen_param_yaml.py {api}', log_file=drv_log)
if rc != 0:
return finish('NO_PARAM_YAML', out.strip().splitlines()[-1] if out.strip() else '')
rc, out = run(f'python scripts/auto_gen_constraint_yaml.py --param_yaml {tdir}/03_参数定义.yaml --output {tdir}/05_约束定义.yaml', log_file=drv_log)
if rc != 0:
return finish('NO_CONSTRAINT_YAML', '')
run(f'python skills/ascendc-st-design/scripts/generate_test_factors.py {tdir}/03_参数定义.yaml {tdir}/04_测试因子.yaml', log_file=drv_log)
run(f'python skills/ascendc-st-design/scripts/generate_implicit_constraints.py {tdir}/04_测试因子.yaml {tdir}/05_约束定义.yaml', log_file=drv_log)
run(f'python skills/ascendc-st-design/scripts/generate_solver_config.py {tdir}/05_约束定义.yaml {tdir}/06_求解配置.yaml', log_file=drv_log)
run(f'python skills/ascendc-st-design/scripts/generate_factor_values.py {tdir}/06_求解配置.yaml {tdir}/05_约束定义.yaml {tdir}/04_测试因子.yaml {tdir}/07_因子值.xlsx --max-cases 1000', log_file=drv_log)
rc, out = run(f'python skills/ascendc-fuzz-cpp-gen/scripts/gen_tiling_key_coverage.py --op_name {api} --param_yaml {tdir}/03_参数定义.yaml --output {tdir}/08_tiling_key_coverage.yaml', log_file=drv_log)
n_tk = 0
m = re.search(r'api_reachable=(\d+)', out)
if m:
n_tk = int(m.group(1))
rec['n_tk'] = n_tk
idx = json.load(open('/tmp/opencode/op_index.json')) if os.path.exists('/tmp/opencode/op_index.json') else {}
md = idx.get(api, {}).get('md', '')
rc, out = run(f'python skills/ascendc-fuzz-cpp-gen/scripts/st_to_fuzz_config.py --param_def {tdir}/03_参数定义.yaml --constraint_def {tdir}/05_约束定义.yaml --api_doc "{md}" --op_name {api} --output {tdir}/fuzz_op_config.yaml', log_file=drv_log)
if rc != 0 or not os.path.exists(f'{tdir}/fuzz_op_config.yaml'):
return finish('CONFIG_FAIL', '')
tiling_arg = f'--tiling_yaml {tdir}/08_tiling_key_coverage.yaml' if n_tk > 0 else ''
rc, out = run(f'python skills/ascendc-fuzz-cpp-gen/scripts/gen_fuzz_cpp.py --op_name {api} --st_config {tdir}/fuzz_op_config.yaml {tiling_arg} --output {OUT}/{api}/', log_file=drv_log)
normal_cpp = os.path.join(OUT, api, f'{api}.cpp')
if rc != 0 or not os.path.exists(normal_cpp):
return finish('GEN_CPP_FAIL', out.strip().splitlines()[-1] if out.strip() else '')
run('rm -f ' + os.path.join(FRAME, 'src/op/*.cpp'))
run(f'cp {normal_cpp} {FRAME}/src/op/')
rc, out = run('make op_fuzz', cwd=FRAME, timeout=600, log_file=drv_log)
if rc != 0:
return finish('COMPILE_FAIL', '')
precheck_log = os.path.join(fdir, f'{api}_fuzz_precheck.log')
final_succ = 0
for attempt in range(3):
clear_plog()
with open(precheck_log, 'w', encoding='utf-8') as lf:
prc = subprocess.run(f'./aclnnAPI_fuzz {api}_fuzz 1000', shell=True, cwd=os.path.join(FRAME, 'out'), stdout=lf, stderr=subprocess.STDOUT, timeout=900, env=ENV).returncode
succ, fail = count_success(precheck_log)
final_succ = succ
rate = succ / 1000.0
rec['precheck'] = f'{succ}/1000={rate:.1%}'
save_status(status)
if rate >= 0.95:
break
n_malloc = 0
try:
n_malloc = open(precheck_log, encoding='utf-8', errors='ignore').read().count('aclrtMalloc failed')
except Exception:
pass
if n_malloc >= 20 and attempt < 2:
cpp = open(normal_cpp, encoding='utf-8').read()
cpp2 = re.sub(r'const long long sizeTargets\[4\] = \{(\d+)LL, (\d+)LL, (\d+)LL, (\d+)LL\};',
lambda mm: 'const long long sizeTargets[4] = {%dLL, %dLL, %dLL, %dLL};' % tuple(max(1000, int(g) // 4) for g in mm.groups()),
cpp)
if cpp2 != cpp:
open(normal_cpp, 'w', encoding='utf-8').write(cpp2)
run('rm -f ' + os.path.join(FRAME, 'src/op/*.cpp'))
run(f'cp {normal_cpp} {FRAME}/src/op/')
run('make op_fuzz', cwd=FRAME, timeout=600, log_file=drv_log)
continue
break
if final_succ < 950:
return finish('PRECHECK_FAIL', f'succ={final_succ}/1000')
rc, out = run(f'python skills/gen-consistent-from-normal/scripts/parse_md_deterministic.py --api {api} --output {tdir}/deterministic_check.json', log_file=drv_log)
need_det = 0
try:
dj = json.load(open(f'{tdir}/deterministic_check.json', encoding='utf-8'))
need_det = 1 if dj.get('need_deterministic') else 0
except Exception:
pass
rec['need_deterministic'] = need_det
rc, out = run(f'python skills/gen-consistent-from-normal/scripts/gen_consistent_from_normal.py --input {normal_cpp} --output {OUT}/{api}/{api}_consistent.cpp --api {api} --deterministic_json {tdir}/deterministic_check.json', log_file=drv_log)
cons_cpp = os.path.join(OUT, api, f'{api}_consistent.cpp')
if rc != 0 or not os.path.exists(cons_cpp):
return finish('GEN_CONSISTENT_FAIL', '')
rc, out = run(f'python skills/gen-consistent-from-normal/scripts/verify_consistent.py --cpp {cons_cpp} --api {api} --need_deterministic {need_det}', log_file=drv_log)
if 'RESULT: PASS' not in out:
return finish('VERIFY_FAIL', out.strip().splitlines()[-1] if out.strip() else '')
run('rm -f ' + os.path.join(FRAME, 'src/src_consistent/*.cpp'))
run(f'cp {cons_cpp} {FRAME}/src/src_consistent/')
rc, out = run('make op_fuzz TARGET=consistent', cwd=FRAME, timeout=600, log_file=drv_log)
if rc != 0:
return finish('COMPILE_CONSISTENT_FAIL', '')
pre_n = max(n_tk * 2, 100) if n_tk > 0 else 100
clear_plog()
pre_log = os.path.join(fdir, f'{api}_consistent_precheck.log')
try:
with open(pre_log, 'w', encoding='utf-8') as lf:
prc = subprocess.run(f'./aclnnAPI_fuzz_consistent {api}_consistent_fuzz {pre_n}', shell=True, cwd=os.path.join(FRAME, 'out'), stdout=lf, stderr=subprocess.STDOUT, timeout=1200, env=ENV).returncode
cs, cm, ce = consistent_stats(pre_log)
except subprocess.TimeoutExpired:
return finish('CONSISTENT_PRECHECK_TIMEOUT', '')
rec['consistent_precheck'] = f'consistent={cs} mismatch={cm} err={ce}/{pre_n}'
save_status(status)
if cs == 0 and cm == 0:
return finish('CONSISTENT_PRECHECK_CRASH', f'rc={prc}')
full_n = min(n_tk * 50, 10000) if n_tk > 0 else 1000
clear_plog()
full_log = os.path.join(fdir, f'{api}_consistent_fuzz_output.log')
with open(full_log, 'w', encoding='utf-8') as lf:
p = subprocess.run(f'./aclnnAPI_fuzz_consistent {api}_consistent_fuzz {full_n}', shell=True, cwd=os.path.join(FRAME, 'out'), stdout=lf, stderr=subprocess.STDOUT, timeout=1800, env=ENV)
if p.returncode != 0:
rec['full_run_rc'] = p.returncode
run(f'cp {PLOG_DIR}/plog-*.log {fdir}/{api}_consistent_fuzz_plog.log 2>/dev/null', log_file=drv_log)
rc, out = run(f'python skills/gen-consistent-from-normal/scripts/parse_consistent_log.py --log {full_log} --api {api} --plog {fdir}/{api}_consistent_fuzz_plog.log --run_num 2', log_file=drv_log)
m = re.search(r'total=(\d+) tks=\d+ consistent=(\d+) hash_mismatch=(\d+) execute_error=(\d+) exception=(\d+) aicore_error=(\w+) need_issue=(\w+)', out)
if m:
rec.update({
'total': int(m.group(1)), 'consistent': int(m.group(2)),
'hash_mismatch': int(m.group(3)), 'execute_error': int(m.group(4)),
'aicore_error': m.group(6), 'need_issue': m.group(7),
})
finish('OK' if int(m.group(3)) == 0 and m.group(6) == 'False' else 'OK_WITH_ISSUE',
f'mismatch={m.group(3)} aicore={m.group(6)}')
else:
finish('PARSE_FAIL', out.strip().splitlines()[-1] if out.strip() else '')
def count_success_from_run(out_text):
s, d = 0, 0
for line in out_text.splitlines():
if '[FUZZ_RESULT]' in line:
if ' success' in line:
s += 1
elif ' faild' in line:
d += 1
return s, d
def main():
ap = argparse.ArgumentParser()
ap.add_argument('api')
args = ap.parse_args()
status = load_status()
pipeline(args.api, status)
if __name__ == '__main__':
main()