"""Mechanical non_contig/normal CPP -> multithread CPP converter.
Supports both base forms:
- non_contig CPP: funcs named {api}_non_contig / {api}_non_contig_fuzz
- normal CPP: funcs named {api}_Normal / {api}_fuzz (contiguous-only ops)
Transformations (ascendc-fuzz-multithread-cpp-gen SKILL.md):
1. Normal func gets (int fuzz_num, aclrtContext context)
2. Init(...) -> aclrtSetCurrentContext(context) + aclrtCreateStream(&stream)
3. DT_FUZZ_START(0,..) -> aclnn_multithread_RANDOM_INT + DT_FUZZ_START(random_int,..)
4. Ending: keep only aclrtDestroyStream(stream)
5. Entry: extern "C" {api}_fuzz(int argc, char *argv[], aclrtContext context)
6. Scene range 2~5 -> 0~5 (if present)
"""
import re
import sys
def convert(api, src, outputs=None):
text = open(src, encoding='utf-8', errors='ignore').read()
text = text.replace('int %s_non_contig(int fuzz_num)' % api,
'int %s_Normal(int fuzz_num, aclrtContext context)' % api)
text = text.replace('int %s_Normal(int fuzz_num)' % api,
'int %s_Normal(int fuzz_num, aclrtContext context)' % api)
text = text.replace('int %s(int fuzz_num)' % api,
'int %s_Normal(int fuzz_num, aclrtContext context)' % api)
init_repl = ('auto ret = aclrtSetCurrentContext(context);\n'
'CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("%s aclrtSetCurrentContext failed. ERROR: %%d\\n", ret); return ret);\n'
'aclrtStream stream;\n'
'ret = aclrtCreateStream(&stream);\n'
'CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("%s aclrtCreateStream failed. ERROR: %%d\\n", ret); return ret);' % (api, api))
pat = re.compile(r'auto ret = Init\(deviceId, &context, &stream\);\s*\n\s*'
r'CHECK_RET\(ret == ACL_SUCCESS, LOG_PRINT\("Init acl failed\. ERROR: %d\\n", ret\); return ret\);')
text, n1 = pat.subn(lambda m: init_repl, text)
if n1 == 0:
text, n1 = re.subn(r'auto ret = Init\(deviceId, &context, &stream\);', lambda m: init_repl, text)
seed_repl = ('int random_int = aclnn_multithread_RANDOM_INT(1, 99999999);\n'
' DT_FUZZ_START(random_int, fuzz_num,')
text, n2 = re.subn(r'DT_FUZZ_START\(0, fuzz_num,', lambda m: seed_repl, text, count=1)
text = re.sub(r'aclrtDestroyStream\(stream\);\s*\n\s*aclrtDestroyContext\(context\);\s*\n\s*aclrtResetDevice\(deviceId\);\s*\n\s*aclFinalize\(\);',
'aclrtDestroyStream(stream);', text)
text = text.replace('extern "C" int %s_non_contig_fuzz(int argc, char *argv[]);' % api,
'extern "C" int %s_fuzz(int argc, char *argv[], aclrtContext context);' % api)
text = text.replace('int %s_non_contig_fuzz(int argc, char *argv[])' % api,
'int %s_fuzz(int argc, char *argv[], aclrtContext context)' % api)
text = text.replace('extern "C" int %s_fuzz(int argc, char *argv[]);' % api,
'extern "C" int %s_fuzz(int argc, char *argv[], aclrtContext context);' % api)
text = re.sub(r'int %s_fuzz\(int argc, char \*argv\[\]\)(?!.*aclrtContext)' % api,
lambda m: 'int %s_fuzz(int argc, char *argv[], aclrtContext context)' % api, text)
text = text.replace('%s_non_contig(fuzz_num)' % api, '%s_Normal(fuzz_num, context)' % api)
text = re.sub(r'printf\("%s(_non_contig)?_Normal :%%d \\n", %s(_non_contig)?_Normal\(fuzz_num\)\);' % (api, api),
lambda m: 'printf("%s_Normal :%%d \\n", %s_Normal(fuzz_num, context));' % (api, api), text)
text = text.replace('%s_Normal(fuzz_num));' % api, '%s_Normal(fuzz_num, context));' % api)
text = re.sub(r'DTSetGetNumberRange\(&g_Element\[i\+\+\], 1, 2, 5, "i"\)',
'DTSetGetNumberRange(&g_Element[i++], 1, 0, 5, "i")', text)
text = re.sub(r'DTSetGetNumberRange\(&g_Element\[i\+\+\], 2, 2, \(ndim >= 2 \? 5 : 4\), "i"\)',
'DTSetGetNumberRange(&g_Element[i++], 2, 0, 5, "i")', text)
text = re.sub(r'if \(nc\w+\.scene < 2\) nc\w+\.scene = 2;\s*\n', '', text)
for out_name in (outputs or []):
cap = out_name[0].upper() + out_name[1:]
old_draw = 'nc%s.scene = *(int *)DTSetGetNumberRange(&g_Element[i++], 1, 0, 5, "i");' % cap
new_draw = ('nc%s.scene = *(int *)DTSetGetNumberRange(&g_Element[i++], 0, 0, 5, "i"); /* [OUT-SCENE-FIX] initValue=0 */\n'
' if (nc%s.scene == 1) { nc%s.scene = 0; } /* [OUT-SCENE-FIX] 输出禁止BROADCAST(gate 1.6) */') % (cap, cap, cap)
if old_draw in text:
text = text.replace(old_draw, new_draw)
else:
old_draw2 = 'nc%s.scene = *(int *)DTSetGetNumberRange(&g_Element[i++], 1, 2, 5, "i");' % cap
if old_draw2 in text:
text = text.replace(old_draw2, new_draw.replace(' 1, 0, 5,', ' 1, 2, 5,').replace('0, 0, 5,', '0, 0, 5,').replace('&g_Element[i++], 0, 0, 5', '&g_Element[i++], 0, 0, 5'))
text = text.replace(' non_contig op fuzz', ' multithread op fuzz')
return text, n1, n2
def main():
if len(sys.argv) < 4:
print('Usage: convert_to_multithread.py <input_cpp> <output_cpp> <api>')
sys.exit(1)
import argparse
ap = argparse.ArgumentParser()
ap.add_argument('input'); ap.add_argument('output'); ap.add_argument('api')
ap.add_argument('--outputs', default='', help='输出tensor名逗号列表(输出scene禁止BROADCAST,gate 1.6)')
args = ap.parse_args()
src, dst, api = args.input, args.output, args.api
outs = [x.strip() for x in args.outputs.split(',') if x.strip()]
out, n_init, n_seed = convert(api, src, outs)
open(dst, 'w', encoding='utf-8').write(out)
ok = []
ok.append(('entry', 'extern "C" int %s_fuzz(int argc, char *argv[], aclrtContext context)' % api in out))
ok.append(('sig', 'int %s_Normal(int fuzz_num, aclrtContext context)' % api in out))
ok.append(('ctx', 'aclrtSetCurrentContext(context)' in out))
ok.append(('seed', 'aclnn_multithread_RANDOM_INT' in out))
ok.append(('no_devdestroy', 'aclrtDestroyContext(context);' not in out.split('aclrtDestroyStream(stream);')[-1]))
has_scene = 'DTSetGetNumberRange(&g_Element[i++], 1, 0, 5, "i")' in out
for name, v in ok:
if not v:
print('[MT_CONVERT_FAIL] check %s failed (init=%d seed=%d)' % (name, n_init, n_seed))
sys.exit(2)
if not has_scene:
print('[MT_CONVERT_WARN] no scene mutation lines (contiguous-only op) - acceptable for md nc=x ops')
print('[MT_CONVERT_OK] %s -> %s' % (src, dst))
if __name__ == '__main__':
main()