已合并
MQSMLA pytest support only run case in excel #8650
MQSMLA pytest support only run case in excel #8650
已合并
郑文惠创建于 7月13日
7 个文件变更+193-82
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/batch/mixed_quant_sparse_flash_mla_process.py+9-7
@@ -28,7 +28,7 @@ class Network(torch.nn.Module):
28 28 
29 def forward(self, q, ori_kv, cmp_kv, cmp_sparse_indices, ori_block_table,29 def forward(self, q, ori_kv, cmp_kv, cmp_sparse_indices, ori_block_table,
30 cmp_block_table, cu_seqlens_q, seqused_q, cu_seqlens_ori_kv, cu_seqlens_cmp_kv,30 cmp_block_table, cu_seqlens_q, seqused_q, cu_seqlens_ori_kv, cu_seqlens_cmp_kv,
31- seqused_ori_kv, seqused_cmp_kv, cmp_residual_kv, sinks, metadata, quant_mode, rope_head_dim,31+ seqused_ori_kv, seqused_cmp_kv, cmp_residual_kv, ori_topk_length, cmp_topk_length, sinks, metadata, quant_mode, rope_head_dim,
32 softmax_scale, cmp_ratio, ori_mask_mode, cmp_mask_mode, ori_win_left, ori_win_right, layout_q, layout_kv,32 softmax_scale, cmp_ratio, ori_mask_mode, cmp_mask_mode, ori_win_left, ori_win_right, layout_q, layout_kv,
33 topk_value_mode, return_softmax_lse):33 topk_value_mode, return_softmax_lse):
34 npu_result, _ = torch.ops.cann_ops_transformer.mixed_quant_sparse_flash_mla(34 npu_result, _ = torch.ops.cann_ops_transformer.mixed_quant_sparse_flash_mla(
@@ -40,14 +40,14 @@ class Network(torch.nn.Module):
40 ori_block_table=ori_block_table,40 ori_block_table=ori_block_table,
41 cmp_block_table=cmp_block_table,41 cmp_block_table=cmp_block_table,
42 cu_seqlens_q=cu_seqlens_q,42 cu_seqlens_q=cu_seqlens_q,
43- cu_seqlens_ori_kv=op_input['cu_seqlens_ori_kv'].npu() if op_input['cu_seqlens_ori_kv'] is not None else None,43+ cu_seqlens_ori_kv=cu_seqlens_ori_kv,
44- cu_seqlens_cmp_kv=op_input['cu_seqlens_cmp_kv'].npu() if op_input['cu_seqlens_cmp_kv'] is not None else None,44+ cu_seqlens_cmp_kv=cu_seqlens_cmp_kv,
45 seqused_q=seqused_q,45 seqused_q=seqused_q,
46 seqused_ori_kv=seqused_ori_kv,46 seqused_ori_kv=seqused_ori_kv,
47 seqused_cmp_kv=seqused_cmp_kv,47 seqused_cmp_kv=seqused_cmp_kv,
48 cmp_residual_kv=cmp_residual_kv,48 cmp_residual_kv=cmp_residual_kv,
49- ori_topk_length=None,49+ ori_topk_length=ori_topk_length,
50- cmp_topk_length=None,50+ cmp_topk_length=cmp_topk_length,
51 sinks=sinks,51 sinks=sinks,
52 metadata=metadata,52 metadata=metadata,
53 quant_mode=quant_mode,53 quant_mode=quant_mode,
@@ -66,7 +66,7 @@ class Network(torch.nn.Module):
66 value_dtype=None)66 value_dtype=None)
67 return npu_result67 return npu_result
68 68 
69-def test_qsmla_quant_process_graph(test_data, device_id=0):69+def test_mqsmla_quant_process_graph(test_data, device_id=0):
70 params = test_data['params']70 params = test_data['params']
71 metadata_input = test_data['metadata_input']71 metadata_input = test_data['metadata_input']
72 op_input = test_data['op_input']72 op_input = test_data['op_input']
@@ -132,6 +132,8 @@ def test_qsmla_quant_process_graph(test_data, device_id=0):
132 cmp_block_table=op_input['cmp_block_table'].npu() if op_input['cmp_block_table'] is not None else None,132 cmp_block_table=op_input['cmp_block_table'].npu() if op_input['cmp_block_table'] is not None else None,
133 cu_seqlens_q=op_input['cu_seqlens_q'].npu() if op_input['cu_seqlens_q'] is not None else None,133 cu_seqlens_q=op_input['cu_seqlens_q'].npu() if op_input['cu_seqlens_q'] is not None else None,
134 seqused_q=op_input['seqused_q'].npu() if op_input['seqused_q'] is not None else torch.tensor([]).npu(),134 seqused_q=op_input['seqused_q'].npu() if op_input['seqused_q'] is not None else torch.tensor([]).npu(),
135+ cu_seqlens_ori_kv=op_input['cu_seqlens_ori_kv'].npu() if op_input['cu_seqlens_ori_kv'] is not None else None,
136+ cu_seqlens_cmp_kv=op_input['cu_seqlens_cmp_kv'].npu() if op_input['cu_seqlens_cmp_kv'] is not None else None,
135 seqused_ori_kv=op_input['seqused_ori_kv'].npu() if op_input['seqused_ori_kv'] is not None else None,137 seqused_ori_kv=op_input['seqused_ori_kv'].npu() if op_input['seqused_ori_kv'] is not None else None,
136 seqused_cmp_kv=op_input['seqused_cmp_kv'].npu() if op_input['seqused_cmp_kv'] is not None else None,138 seqused_cmp_kv=op_input['seqused_cmp_kv'].npu() if op_input['seqused_cmp_kv'] is not None else None,
137 cmp_residual_kv=op_input['cmp_residual_kv'].npu() if op_input['cmp_residual_kv'] is not None else None,139 cmp_residual_kv=op_input['cmp_residual_kv'].npu() if op_input['cmp_residual_kv'] is not None else None,
@@ -155,7 +157,7 @@ def test_qsmla_quant_process_graph(test_data, device_id=0):
155 torch.npu.synchronize()157 torch.npu.synchronize()
156 return npu_result, cpu_output158 return npu_result, cpu_output
157 159 
158-def test_qsmla_quant_process_ci(test_data, device_id=0):160+def test_mqsmla_quant_process_ci(test_data, device_id=0):
159 params = test_data['params']161 params = test_data['params']
160 metadata_input = test_data['metadata_input']162 metadata_input = test_data['metadata_input']
161 op_input = test_data['op_input']163 op_input = test_data['op_input']
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/batch/test_mixed_quant_sparse_flash_mla_pt_save.py+6-6
@@ -26,9 +26,9 @@ import argparse
26import concurrent.futures26import concurrent.futures
27 27 
28# 读取表格(支持通过环境变量传入)28# 读取表格(支持通过环境变量传入)
29-save_path = os.environ.get("QSMLA_PT_DIR", "qsmla_testcase")29+save_path = os.environ.get("MQSMLA_PT_DIR", "mqsmla_testcase")
30-excel_file = os.environ.get("QSMLA_EXCEL", "./excel/example.xlsx")30+excel_file = os.environ.get("MQSMLA_EXCEL", "./excel/example.xlsx")
31-sheet_name = os.environ.get("QSMLA_SHEET", "decode")31+sheet_name = os.environ.get("MQSMLA_SHEET", "decode")
32ENABLED_PARAMS = utils.load_excel_test_cases(excel_file, sheet_name)32ENABLED_PARAMS = utils.load_excel_test_cases(excel_file, sheet_name)
33 33 
34param_combinations = []34param_combinations = []
@@ -108,7 +108,7 @@ for _, params in enumerate(ENABLED_PARAMS):
108 print(param_combinations)108 print(param_combinations)
109 109 
110case_id = 0110case_id = 0
111-def qsmla(param_combinations):111+def mqsmla(param_combinations):
112 global case_id112 global case_id
113 params = utils.fill_none_params(param_combinations)113 params = utils.fill_none_params(param_combinations)
114 114 
@@ -118,7 +118,7 @@ def qsmla(param_combinations):
118 q_type_str = "BF16" if params['q_type'] == torch.bfloat16 else "FP16"118 q_type_str = "BF16" if params['q_type'] == torch.bfloat16 else "FP16"
119 kv_type_str = "HIF8" if params['ori_kv_type'] == torch.uint8 else "FP8_E4M3FN"119 kv_type_str = "HIF8" if params['ori_kv_type'] == torch.uint8 else "FP8_E4M3FN"
120 prefix_part = f"{param_combinations['tc_prefix']}_"if param_combinations.get('tc_prefix', '') else ""120 prefix_part = f"{param_combinations['tc_prefix']}_"if param_combinations.get('tc_prefix', '') else ""
121- Testcase_Name = f"QSMLA_{prefix_part}{params['template_run_mode']}_{ops_mode}_{params['layout_q']}_{q_type_str}_{params['layout_kv']}_{kv_type_str}_{params['B']}_{params['N1']}_{params['N2']}_{params['S1']}_{params['S2']}_{params['D']}_{params['K']}_{params['rope_head_dim']}_{case_id:06d}"121+ Testcase_Name = f"MQSMLA_{prefix_part}{params['template_run_mode']}_{ops_mode}_{params['layout_q']}_{q_type_str}_{params['layout_kv']}_{kv_type_str}_{params['B']}_{params['N1']}_{params['N2']}_{params['S1']}_{params['S2']}_{params['D']}_{params['K']}_{params['rope_head_dim']}_{case_id:06d}"
122 params['Testcase_Name'] = Testcase_Name122 params['Testcase_Name'] = Testcase_Name
123 print("input_params:", params)123 print("input_params:", params)
124 124 
@@ -137,7 +137,7 @@ def qsmla(param_combinations):
137def test_mixed_quant_sparse_flash_mla(param_combinations): # 初始化参数和tensor137def test_mixed_quant_sparse_flash_mla(param_combinations): # 初始化参数和tensor
138 # 线程池138 # 线程池
139 with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:139 with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
140- futures = executor.submit(qsmla, param_combinations)140+ futures = executor.submit(mqsmla, param_combinations)
141 # 等待并获取结果141 # 等待并获取结果
142 for future in concurrent.futures.as_completed([futures]):142 for future in concurrent.futures.as_completed([futures]):
143 try:143 try:
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/mixed_quant_sparse_flash_mla_paramset.py+1-1
@@ -41,7 +41,7 @@ TEST_PARAMS = {
41 "softmax_scale": [0.04419417],41 "softmax_scale": [0.04419417],
42 "cmp_ratio": [1],42 "cmp_ratio": [1],
43 "ori_mask_mode": [4],43 "ori_mask_mode": [4],
44- "cmp_mask_mode": [3],44+ "cmp_mask_mode": [0],
45 "ori_win_left": [127],45 "ori_win_left": [127],
46 "ori_win_right": [0],46 "ori_win_right": [0],
47 "quant_mode": [1],47 "quant_mode": [1],
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/test_mixed_quant_sparse_flash_mla_batch.py+35-14
@@ -26,28 +26,49 @@ import check_valid_param
26from batch import mixed_quant_sparse_flash_mla_process26from batch import mixed_quant_sparse_flash_mla_process
27import utils27import utils
28 28 
29-testcase_path = os.environ.get("QSMLA_PT_DIR", "qsmla_testcase")29+testcase_path = os.environ.get("MQSMLA_PT_DIR", "mqsmla_testcase")
30-result_path = Path('result.xlsx')30+batch_test_mode = int(os.environ.get("MQSMLA_BATCH_TEST_MODE", 0)) # 0:路径下全量批跑,1:按表格中case批跑
31-device_id=031+excel_path = os.environ.get("MQSMLA_EXCEL_PATH", os.path.join(os.path.dirname(__file__), "excel", "testcase.xlsx"))
32+result_path = os.environ.get("MQSMLA_RESULT_SAVE_PATH", './mqsmla_result.xlsx')
33+device_id = int(os.environ.get("MQSMLA_DEVICE_ID", 0))
32 34 
33testcase_files = []35testcase_files = []
34if os.path.isdir(testcase_path):36if os.path.isdir(testcase_path):
35- pt_files = [f for f in os.listdir(testcase_path) if f.endswith('.pt')]37+ if batch_test_mode == 1:
36- if not pt_files:38+ df = pd.read_excel(excel_path)
37- print(f"错误: 目录中没有找到.pt文件: {testcase_path}")39+ target_names = [str(name) for name in df['Testcase_Name'].dropna().tolist() if str(name) != 'None']
40+ if not target_names:
41+ print(f"错误: 表格中没有有效的Testcase_Name: {excel_path}")
42+ else:
43+ print(f"从表格中读取到 {len(target_names)} 个目标用例名")
44+ pt_files = [f for f in os.listdir(testcase_path) if f.endswith('.pt')]
45+ for target_name in target_names:
46+ matched = [f for f in pt_files if target_name in f]
47+ if matched:
48+ for f in matched:
49+ filepath = os.path.join(testcase_path, f)
50+ if filepath not in testcase_files:
51+ testcase_files.append(filepath)
52+ else:
53+ print(f"警告: 用例名 '{target_name}' 未匹配到任何.pt文件")
54+ print(f"按表格筛选后共 {len(testcase_files)} 个测试用例文件")
38 else:55 else:
39- print(f"找到 {len(pt_files)} 个测试用例文件")56+ pt_files = [f for f in os.listdir(testcase_path) if f.endswith('.pt')]
40- for pt_file in pt_files:57+ if not pt_files:
41- filepath = os.path.join(testcase_path, pt_file)58+ print(f"错误: 目录中没有找到.pt文件: {testcase_path}")
42- testcase_files.append(filepath)59+ else:
60+ print(f"找到 {len(pt_files)} 个测试用例文件")
61+ for pt_file in pt_files:
62+ filepath = os.path.join(testcase_path, pt_file)
63+ testcase_files.append(filepath)
43else:64else:
44 print(f"错误: 输出目录不存在: {testcase_path}")65 print(f"错误: 输出目录不存在: {testcase_path}")
45 66 
46-def qsmla(testcase_files):67+def mqsmla(testcase_files):
47 test_data = torch.load(testcase_files, map_location="cpu")68 test_data = torch.load(testcase_files, map_location="cpu")
48 npu_error_msg = None69 npu_error_msg = None
49 try:70 try:
50- npu_result, cpu_quant_result = mixed_quant_sparse_flash_mla_process.test_qsmla_quant_process_ci(71+ npu_result, cpu_quant_result = mixed_quant_sparse_flash_mla_process.test_mqsmla_quant_process_ci(
51 test_data, device_id=device_id)72 test_data, device_id=device_id)
52 result, fulfill_percent = result_compare_method.check_result(cpu_quant_result, npu_result)73 result, fulfill_percent = result_compare_method.check_result(cpu_quant_result, npu_result)
53 except Exception as e:74 except Exception as e:
@@ -56,7 +77,7 @@ def qsmla(testcase_files):
56 result = "NPU ERROR"77 result = "NPU ERROR"
57 fulfill_percent = 078 fulfill_percent = 0
58 79 
59- utils.save_result(test_data['params'], result, fulfill_percent, result_path)80+ utils.save_result(test_data['params'], result, fulfill_percent, Path(result_path))
60 81 
61 if result == "Failed":82 if result == "Failed":
62 pytest.fail(f"用例精度失败:{test_data['Testcase_Name']} 精度:{fulfill_percent:.2f}%")83 pytest.fail(f"用例精度失败:{test_data['Testcase_Name']} 精度:{fulfill_percent:.2f}%")
@@ -70,7 +91,7 @@ testcase_ids = [os.path.splitext(os.path.basename(f))[0] for f in testcase_files
70def test_mixed_quant_sparse_flash_mla(testcase_files):91def test_mixed_quant_sparse_flash_mla(testcase_files):
71 # 线程池92 # 线程池
72 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:93 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
73- futures = executor.submit(qsmla, testcase_files)94+ futures = executor.submit(mqsmla, testcase_files)
74 # 等待并获取结果95 # 等待并获取结果
75 for future in concurrent.futures.as_completed([futures]):96 for future in concurrent.futures.as_completed([futures]):
76 try:97 try:
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/test_mixed_quant_sparse_flash_mla_batch_graph.py+35-14
@@ -26,28 +26,49 @@ import check_valid_param
26from batch import mixed_quant_sparse_flash_mla_process26from batch import mixed_quant_sparse_flash_mla_process
27import utils27import utils
28 28 
29-testcase_path = "qsmla_testcase"29+testcase_path = os.environ.get("MQSMLA_PT_DIR", "mqsmla_testcase")
30-result_path = Path('result.xlsx') # 或使用传入的result_path30+batch_test_mode = int(os.environ.get("MQSMLA_BATCH_TEST_MODE", 0)) # 0:路径下全量批跑,1:按表格中case批跑
31-device_id=031+excel_path = os.environ.get("MQSMLA_EXCEL_PATH", os.path.join(os.path.dirname(__file__), "excel", "testcase.xlsx"))
32+result_path = os.environ.get("MQSMLA_RESULT_SAVE_PATH", './mqsmla_result.xlsx')
33+device_id = int(os.environ.get("MQSMLA_DEVICE_ID", 0))
32 34 
33locals()["testcase_files"] = []35locals()["testcase_files"] = []
34if os.path.isdir(testcase_path):36if os.path.isdir(testcase_path):
35- pt_files = [f for f in os.listdir(testcase_path) if f.endswith('.pt')]37+ if batch_test_mode == 1:
36- if not pt_files:38+ df = pd.read_excel(excel_path)
37- print(f"错误: 目录中没有找到.pt文件: {testcase_path}")39+ target_names = [str(name) for name in df['Testcase_Name'].dropna().tolist() if str(name) != 'None']
40+ if not target_names:
41+ print(f"错误: 表格中没有有效的Testcase_Name: {excel_path}")
42+ else:
43+ print(f"从表格中读取到 {len(target_names)} 个目标用例名")
44+ pt_files = [f for f in os.listdir(testcase_path) if f.endswith('.pt')]
45+ for target_name in target_names:
46+ matched = [f for f in pt_files if target_name in f]
47+ if matched:
48+ for f in matched:
49+ filepath = os.path.join(testcase_path, f)
50+ if filepath not in locals()["testcase_files"]:
51+ locals()["testcase_files"].append(filepath)
52+ else:
53+ print(f"警告: 用例名 '{target_name}' 未匹配到任何.pt文件")
54+ print(f"按表格筛选后共 {len(locals()['testcase_files'])} 个测试用例文件")
38 else:55 else:
39- print(f"找到 {len(pt_files)} 个测试用例文件")56+ pt_files = [f for f in os.listdir(testcase_path) if f.endswith('.pt')]
40- for pt_file in pt_files:57+ if not pt_files:
41- filepath = os.path.join(testcase_path, pt_file)58+ print(f"错误: 目录中没有找到.pt文件: {testcase_path}")
42- locals()["testcase_files"].append(filepath)59+ else:
60+ print(f"找到 {len(pt_files)} 个测试用例文件")
61+ for pt_file in pt_files:
62+ filepath = os.path.join(testcase_path, pt_file)
63+ locals()["testcase_files"].append(filepath)
43else:64else:
44 print(f"错误: 输出目录不存在: {testcase_path}")65 print(f"错误: 输出目录不存在: {testcase_path}")
45 66 
46-def qsmla_aclgraph(testcase_files):67+def mqsmla_aclgraph(testcase_files):
47 test_data = torch.load(testcase_files, map_location="cpu")68 test_data = torch.load(testcase_files, map_location="cpu")
48 npu_error_msg = None69 npu_error_msg = None
49 try:70 try:
50- npu_result, cpu_quant_result = mixed_quant_sparse_flash_mla_process.test_qsmla_quant_process_graph(71+ npu_result, cpu_quant_result = mixed_quant_sparse_flash_mla_process.test_mqsmla_quant_process_graph(
51 test_data, device_id=device_id)72 test_data, device_id=device_id)
52 result, fulfill_percent = result_compare_method.check_result(cpu_quant_result, npu_result)73 result, fulfill_percent = result_compare_method.check_result(cpu_quant_result, npu_result)
53 except Exception as e:74 except Exception as e:
@@ -56,7 +77,7 @@ def qsmla_aclgraph(testcase_files):
56 result = "NPU ERROR"77 result = "NPU ERROR"
57 fulfill_percent = 078 fulfill_percent = 0
58 79 
59- utils.save_result(test_data['params'], result, fulfill_percent, result_path)80+ utils.save_result(test_data['params'], result, fulfill_percent, Path(result_path))
60 81 
61 if result == "Failed":82 if result == "Failed":
62 pytest.fail(f"用例精度失败:{test_data['Testcase_Name']} 精度:{fulfill_percent:.2f}%")83 pytest.fail(f"用例精度失败:{test_data['Testcase_Name']} 精度:{fulfill_percent:.2f}%")
@@ -70,7 +91,7 @@ testcase_ids = [os.path.splitext(os.path.basename(f))[0] for f in locals()["test
70def test_mixed_quant_sparse_flash_mla(testcase_files):91def test_mixed_quant_sparse_flash_mla(testcase_files):
71 # 线程池92 # 线程池
72 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:93 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
73- futures = executor.submit(qsmla_aclgraph, testcase_files)94+ futures = executor.submit(mqsmla_aclgraph, testcase_files)
74 # 等待并获取结果95 # 等待并获取结果
75 for future in concurrent.futures.as_completed([futures]):96 for future in concurrent.futures.as_completed([futures]):
76 try:97 try:
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/test_mixed_quant_sparse_flash_mla_single.py+4-4
@@ -26,7 +26,7 @@ import multiprocessing as mp
26import concurrent.futures26import concurrent.futures
27import utils27import utils
28 28 
29-pt_save_path = "qsmla_testcase"29+pt_save_path = "mqsmla_testcase"
30device_id = 030device_id = 0
31save_pt = False31save_pt = False
32result_path = Path('result.xlsx')32result_path = Path('result.xlsx')
@@ -80,7 +80,7 @@ for params in ENABLED_PARAMS:
80 param_combinations.append(combination)80 param_combinations.append(combination)
81 81 
82case_id = 082case_id = 0
83-def qsmla(param_combinations):83+def mqsmla(param_combinations):
84 global case_id84 global case_id
85 85 
86 # 填充None参数的默认值86 # 填充None参数的默认值
@@ -108,7 +108,7 @@ def qsmla(param_combinations):
108 # 获得cpu结果(真值)和算子结果(测试值)108 # 获得cpu结果(真值)和算子结果(测试值)
109 npu_error_msg = None109 npu_error_msg = None
110 try:110 try:
111- npu_result, cpu_quant_result = mixed_quant_sparse_flash_mla_process.test_qsmla_quant_process_ci(111+ npu_result, cpu_quant_result = mixed_quant_sparse_flash_mla_process.test_mqsmla_quant_process_ci(
112 test_data, device_id=device_id)112 test_data, device_id=device_id)
113 result, fulfill_percent = result_compare_method.check_result(cpu_quant_result, npu_result)113 result, fulfill_percent = result_compare_method.check_result(cpu_quant_result, npu_result)
114 except Exception as e:114 except Exception as e:
@@ -142,7 +142,7 @@ testcase_ids = [_gen_testcase_id(p, i) for i, p in enumerate(param_combinations)
142def test_mixed_quant_sparse_flash_mla(param_combinations):142def test_mixed_quant_sparse_flash_mla(param_combinations):
143 # 线程池143 # 线程池
144 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:144 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
145- futures = executor.submit(qsmla, param_combinations)145+ futures = executor.submit(mqsmla, param_combinations)
146 # 等待并获取结果146 # 等待并获取结果
147 for future in concurrent.futures.as_completed([futures]):147 for future in concurrent.futures.as_completed([futures]):
148 try:148 try:
Mattention/mixed_quant_sparse_flash_mla/tests/pytest/test_run.sh+103-36
@@ -11,34 +11,34 @@
11 11 
12set -euo pipefail12set -euo pipefail
13 13 
14-# 脚本路径
15QSMLA_PT_SAVE_SCRIPT="./batch/test_mixed_quant_sparse_flash_mla_pt_save.py"14QSMLA_PT_SAVE_SCRIPT="./batch/test_mixed_quant_sparse_flash_mla_pt_save.py"
16TEST_QSMLA_PT_BATCH_SCRIPT="test_mixed_quant_sparse_flash_mla_batch.py"15TEST_QSMLA_PT_BATCH_SCRIPT="test_mixed_quant_sparse_flash_mla_batch.py"
16+TEST_QSMLA_PT_BATCH_GRAPH_SCRIPT="test_mixed_quant_sparse_flash_mla_batch_graph.py"
17TEST_QSMLA_SINGLE_SCRIPT="test_mixed_quant_sparse_flash_mla_single.py"17TEST_QSMLA_SINGLE_SCRIPT="test_mixed_quant_sparse_flash_mla_single.py"
18 18 
19-# 默认参数19+PT_SAVE_DIR="mqsmla_testcase"
20-PT_SAVE_DIR="qsmla_testcase"
21EXCEL_FILE="./excel/example.xlsx"20EXCEL_FILE="./excel/example.xlsx"
22SHEET_NAME="decode"21SHEET_NAME="decode"
23KEEP_PT=false22KEEP_PT=false
23+BATCH_TEST_MODE=1
24+RESULT_PATH="./mqsmla_result.xlsx"
25+DEVICE_ID=0
24 26 
25# ====================== 执行区 ======================27# ====================== 执行区 ======================
26 28 
27-# 单用例算子调测
28run_single() {29run_single() {
29 echo "===== 执行单用例算子调测 ====="30 echo "===== 执行单用例算子调测 ====="
30 python3 -m pytest -rA -s $TEST_QSMLA_SINGLE_SCRIPT -v -m ci -W ignore::UserWarning -W ignore::DeprecationWarning31 python3 -m pytest -rA -s $TEST_QSMLA_SINGLE_SCRIPT -v -m ci -W ignore::UserWarning -W ignore::DeprecationWarning
31}32}
32 33 
33-# 批量从excel读取用例、golden计算并保存pt文件
34run_batch_save() {34run_batch_save() {
35 echo "===== 执行batch_save:从excel读取用例并保存pt文件 ====="35 echo "===== 执行batch_save:从excel读取用例并保存pt文件 ====="
36 echo " excel: $EXCEL_FILE"36 echo " excel: $EXCEL_FILE"
37 echo " sheet: $SHEET_NAME"37 echo " sheet: $SHEET_NAME"
38 echo " pt目录: $PT_SAVE_DIR"38 echo " pt目录: $PT_SAVE_DIR"
39- export QSMLA_EXCEL="$EXCEL_FILE"39+ export MQSMLA_EXCEL="$EXCEL_FILE"
40- export QSMLA_SHEET="$SHEET_NAME"40+ export MQSMLA_SHEET="$SHEET_NAME"
41- export QSMLA_PT_DIR="$PT_SAVE_DIR"41+ export MQSMLA_PT_DIR="$PT_SAVE_DIR"
42 python3 -m pytest -rA -s $QSMLA_PT_SAVE_SCRIPT -v -m ci -W ignore::UserWarning -W ignore::DeprecationWarning42 python3 -m pytest -rA -s $QSMLA_PT_SAVE_SCRIPT -v -m ci -W ignore::UserWarning -W ignore::DeprecationWarning
43 if [ $? -ne 0 ]; then43 if [ $? -ne 0 ]; then
44 echo "batch_save 执行失败,退出"44 echo "batch_save 执行失败,退出"
@@ -47,7 +47,6 @@ run_batch_save() {
47 echo -e "\n===== batch_save 完成!pt文件保存在 $PT_SAVE_DIR 目录 ====="47 echo -e "\n===== batch_save 完成!pt文件保存在 $PT_SAVE_DIR 目录 ====="
48}48}
49 49 
50-# 批量读取pt文件并执行NPU测试
51run_batch_exec() {50run_batch_exec() {
52 echo "===== 执行batch_exec:读取pt文件并执行NPU测试 ====="51 echo "===== 执行batch_exec:读取pt文件并执行NPU测试 ====="
53 52 
@@ -63,7 +62,11 @@ run_batch_exec() {
63 fi62 fi
64 63 
65 echo "找到 $pt_count 个pt文件,开始执行NPU测试"64 echo "找到 $pt_count 个pt文件,开始执行NPU测试"
66- export QSMLA_PT_DIR="$PT_SAVE_DIR"65+ export MQSMLA_PT_DIR="$PT_SAVE_DIR"
66+ export MQSMLA_BATCH_TEST_MODE="$BATCH_TEST_MODE"
67+ export MQSMLA_EXCEL_PATH="$EXCEL_FILE"
68+ export MQSMLA_RESULT_SAVE_PATH="$RESULT_PATH"
69+ export MQSMLA_DEVICE_ID="$DEVICE_ID"
67 python3 -m pytest -rA -s $TEST_QSMLA_PT_BATCH_SCRIPT -v -m ci -W ignore::UserWarning -W ignore::DeprecationWarning70 python3 -m pytest -rA -s $TEST_QSMLA_PT_BATCH_SCRIPT -v -m ci -W ignore::UserWarning -W ignore::DeprecationWarning
68 if [ $? -ne 0 ]; then71 if [ $? -ne 0 ]; then
69 echo "batch_exec 执行失败"72 echo "batch_exec 执行失败"
@@ -73,7 +76,35 @@ run_batch_exec() {
73 echo -e "\n===== batch_exec 完成!====="76 echo -e "\n===== batch_exec 完成!====="
74}77}
75 78 
76-# 批量从excel读取用例、生成pt文件并执行NPU测试79+run_batch_exec_graph() {
80+ echo "===== 执行batch_exec_graph:读取pt文件并执行Graph模式NPU测试 ====="
81+ 
82+ if [ ! -d "$PT_SAVE_DIR" ]; then
83+ echo "错误: pt文件目录不存在: $PT_SAVE_DIR,请先执行 batch_save 生成pt文件"
84+ exit 1
85+ fi
86+ 
87+ pt_count=$(ls -1 $PT_SAVE_DIR/*.pt 2>/dev/null | wc -l)
88+ if [ $pt_count -eq 0 ]; then
89+ echo "错误: 目录中没有找到.pt文件: $PT_SAVE_DIR,请先执行 batch_save 生成pt文件"
90+ exit 1
91+ fi
92+ 
93+ echo "找到 $pt_count 个pt文件,开始执行Graph模式NPU测试"
94+ export MQSMLA_PT_DIR="$PT_SAVE_DIR"
95+ export MQSMLA_BATCH_TEST_MODE="$BATCH_TEST_MODE"
96+ export MQSMLA_EXCEL_PATH="$EXCEL_FILE"
97+ export MQSMLA_RESULT_SAVE_PATH="$RESULT_PATH"
98+ export MQSMLA_DEVICE_ID="$DEVICE_ID"
99+ python3 -m pytest -rA -s $TEST_QSMLA_PT_BATCH_GRAPH_SCRIPT -v -m graph -W ignore::UserWarning -W ignore::DeprecationWarning
100+ if [ $? -ne 0 ]; then
101+ echo "batch_exec_graph 执行失败"
102+ exit 1
103+ fi
104+ 
105+ echo -e "\n===== batch_exec_graph 完成!====="
106+}
107+ 
77run_batch() {108run_batch() {
78 echo "===== 执行batch:从excel批量生成pt并执行NPU测试 ====="109 echo "===== 执行batch:从excel批量生成pt并执行NPU测试 ====="
79 110 
@@ -89,10 +120,9 @@ run_batch() {
89 exit 1120 exit 1
90 fi121 fi
91 122 
92- # 根据KEEP_PT决定是否清理pt文件
93 if [ "$KEEP_PT" = false ]; then123 if [ "$KEEP_PT" = false ]; then
94 echo -e "\n===== 清理pt文件(KEEP_PT=false) ====="124 echo -e "\n===== 清理pt文件(KEEP_PT=false) ====="
95- [ -n "$PT_SAVE_DIR"] && rm -rf $PT_SAVE_DIR125+ [ -n "$PT_SAVE_DIR" ] && rm -rf $PT_SAVE_DIR
96 echo "pt文件已清理"126 echo "pt文件已清理"
97 else127 else
98 echo -e "\n===== 保留pt文件(KEEP_PT=true)保存在 $PT_SAVE_DIR ====="128 echo -e "\n===== 保留pt文件(KEEP_PT=true)保存在 $PT_SAVE_DIR ====="
@@ -101,37 +131,49 @@ run_batch() {
101 echo -e "\n===== batch 全流程执行完成!====="131 echo -e "\n===== batch 全流程执行完成!====="
102}132}
103 133 
104-# 显示帮助信息
105show_help() {134show_help() {
106 echo "用法: $0 <命令> [选项]"135 echo "用法: $0 <命令> [选项]"
107 echo ""136 echo ""
108 echo "命令说明:"137 echo "命令说明:"
109- echo " single 执行单算子用例调测"138+ echo " single 执行单算子用例调测"
110- echo " batch_save 从excel读取用例,golden计算并保存pt文件"139+ echo " batch_save 从excel读取用例,golden计算并保存pt文件"
111- echo " batch_exec 批量读取pt文件并执行NPU测试"140+ echo " batch_exec 批量读取pt文件并执行NPU测试(CI模式)"
112- echo " batch 全流程:从excel生成pt + NPU测试"141+ echo " batch_exec_graph 批量读取pt文件并执行Graph模式NPU测试"
113- echo " help 显示本帮助信息"142+ echo " batch 全流程:从excel生成pt + NPU测试"
143+ echo " help 显示本帮助信息"
114 echo ""144 echo ""
115- echo "选项(batch_save/batch_exec/batch 命令支持):"145+ echo "选项(batch_save/batch_exec/batch_exec_graph/batch 命令支持):"
116- echo " --excel <路径> 指定excel文件路径(默认: ./excel/example.xlsx)"146+ echo " --excel <路径> 指定excel文件路径(默认: ./excel/example.xlsx)"
117- echo " --sheet <名称> 指定excel sheet名(默认: decode)"147+ echo " --sheet <名称> 指定excel sheet名(默认: decode)"
118- echo " --pt-dir <目录> 指定pt文件保存/读取目录(默认: qsmla_testcase)"148+ echo " --pt-dir <目录> 指定pt文件保存/读取目录(默认: mqsmla_testcase)"
119- echo " --keep-pt 执行完成后留pt文件(默认清理,仅batch命令)"149+ echo " --result <路径> 指定结果存路径(默认: ./mqsmla_result.xlsx)"
150+ echo " --device-id <id> 指定NPU设备ID(默认: 0)"
151+ echo " --mode <0|1> 批跑模式: 0=全量批跑(默认), 1=按表格中case批跑"
152+ echo " --keep-pt 执行完成后保留pt文件(默认清理,仅batch命令)"
153+ echo ""
154+ echo "环境变量(.py文件读取):"
155+ echo " MQSMLA_PT_DIR pt文件目录(batch_save/batch_exec/batch_exec_graph)"
156+ echo " MQSMLA_EXCEL excel文件路径(batch_save)"
157+ echo " MQSMLA_SHEET excel sheet名(batch_save)"
158+ echo " MQSMLA_EXCEL_PATH excel文件路径(batch_exec/batch_exec_graph,mode=1时使用)"
159+ echo " MQSMLA_BATCH_TEST_MODE 批跑模式: 0=全量, 1=按表格(batch_exec/batch_exec_graph)"
160+ echo " MQSMLA_RESULT_SAVE_PATH 结果保存路径(batch_exec/batch_exec_graph)"
161+ echo " MQSMLA_DEVICE_ID NPU设备ID(batch_exec/batch_exec_graph)"
120 echo ""162 echo ""
121 echo "示例:"163 echo "示例:"
122- echo " $0 single # 执行single模式"164+ echo " $0 single"
123- echo " $0 batch_save # 用默认参数生成pt文件"165+ echo " $0 batch_save"
124- echo " $0 batch_save --excel my.xlsx --sheet prefill --pt-dir my_pt"166+ echo " $0 batch_save --excel my.xlsx --sheet decode --pt-dir my_pt"
125- echo " $0 batch_exec # 用默认pt目录执行NPU测试"167+ echo " $0 batch_exec # 全量批跑"
126- echo " $0 batch_exec --pt-dir my_pt # 从指定目录读取pt文件"168+ echo " $0 batch_exec --mode 1 --excel ./excel/testcase.xlsx # 按表格批跑"
127- echo " $0 batch # 全流程,完成后清理pt文件"169+ echo " $0 batch_exec --pt-dir my_pt --result ./my_result.xlsx"
128- echo " $0 batch --keep-pt # 全流程,完成后保留pt文件"170+ echo " $0 batch_exec_graph --mode 1 # Graph模式按表格批跑"
129- echo " $0 batch --excel my.xlsx --sheet prefill --pt-dir my_pt --keep-pt"171+ echo " $0 batch --keep-pt"
172+ echo " $0 batch --excel my.xlsx --sheet decode --pt-dir my_pt --mode 1 --keep-pt"
130}173}
131 174 
132# ====================== 主逻辑 ======================175# ====================== 主逻辑 ======================
133 176 
134-# 解析参数
135if [ $# -lt 1 ]; then177if [ $# -lt 1 ]; then
136 echo "错误:必须传入至少一个命令参数"178 echo "错误:必须传入至少一个命令参数"
137 show_help179 show_help
@@ -141,8 +183,7 @@ fi
141COMMAND="$1"183COMMAND="$1"
142shift184shift
143 185 
144-# 解析选项(batch_save/batch_exec/batch 共用)186+if [ "$COMMAND" = "batch_save" ] || [ "$COMMAND" = "batch_exec" ] || [ "$COMMAND" = "batch_exec_graph" ] || [ "$COMMAND" = "batch" ]; then
145-if [ "$COMMAND" = "batch_save" ] || [ "$COMMAND" = "batch_exec" ] || [ "$COMMAND" = "batch" ]; then
146 while [ $# -gt 0 ]; do187 while [ $# -gt 0 ]; do
147 case "$1" in188 case "$1" in
148 --excel)189 --excel)
@@ -169,6 +210,30 @@ if [ "$COMMAND" = "batch_save" ] || [ "$COMMAND" = "batch_exec" ] || [ "$COMMAND
169 PT_SAVE_DIR="$2"210 PT_SAVE_DIR="$2"
170 shift 2211 shift 2
171 ;;212 ;;
213+ --result)
214+ if [ $# -lt 2 ]; then
215+ echo "错误:--result 需要参数值"
216+ exit 1
217+ fi
218+ RESULT_PATH="$2"
219+ shift 2
220+ ;;
221+ --device-id)
222+ if [ $# -lt 2 ]; then
223+ echo "错误:--device-id 需要参数值"
224+ exit 1
225+ fi
226+ DEVICE_ID="$2"
227+ shift 2
228+ ;;
229+ --mode)
230+ if [ $# -lt 2 ]; then
231+ echo "错误:--mode 需要参数值"
232+ exit 1
233+ fi
234+ BATCH_TEST_MODE="$2"
235+ shift 2
236+ ;;
172 --keep-pt)237 --keep-pt)
173 if [ "$COMMAND" != "batch" ]; then238 if [ "$COMMAND" != "batch" ]; then
174 echo "错误:--keep-pt 仅适用于 batch 命令"239 echo "错误:--keep-pt 仅适用于 batch 命令"
@@ -186,7 +251,6 @@ if [ "$COMMAND" = "batch_save" ] || [ "$COMMAND" = "batch_exec" ] || [ "$COMMAND
186 done251 done
187fi252fi
188 253 
189-# 根据命令执行对应函数
190case "$COMMAND" in254case "$COMMAND" in
191 single)255 single)
192 run_single256 run_single
@@ -197,6 +261,9 @@ case "$COMMAND" in
197 batch_exec)261 batch_exec)
198 run_batch_exec262 run_batch_exec
199 ;;263 ;;
264+ batch_exec_graph)
265+ run_batch_exec_graph
266+ ;;
200 batch)267 batch)
201 run_batch268 run_batch
202 ;;269 ;;