已合并
update the ci framework #2785
wx_4e191bb7af创建于 2025年6月7日
update the ci framework #2785
已合并
wx_4e191bb7af创建于 2025年6月7日
从refs/pull/2785/head合入到master
共 4 个文件变更+70-11
@@ -34,6 +34,10 @@ def is_txt(file):
34 return file.endswith(".txt")34 return file.endswith(".txt")
35 35 
36 36 
37+def is_json(file):
38+ return file.endswith(".json")
39+ 
40+ 
37def is_owners(file):41def is_owners(file):
38 return file.startswith("OWNERS")42 return file.startswith("OWNERS")
39 43 
@@ -72,7 +76,8 @@ def choose_skip_ci(raw_txt_file):
72 is_license,76 is_license,
73 is_no_suffix,77 is_no_suffix,
74 is_poc,78 is_poc,
75- is_0day79+ is_0day,
80+ is_json
76 ]81 ]
77 82 
78 return skip_ci(file_list, skip_conds)83 return skip_ci(file_list, skip_conds)
@@ -16,6 +16,23 @@
16 6.782255E+00,16 6.782255E+00,
17 6.936630E+0017 6.936630E+00
18 ],18 ],
19+ "time info": [
20+ 198136.5,
21+ 2825.0,
22+ 2810.4,
23+ 2820.2,
24+ 2818.4,
25+ 2817.1,
26+ 2812.5,
27+ 2818.4,
28+ 2821.2,
29+ 2827.7,
30+ 2822.8,
31+ 2820.3,
32+ 2824.8,
33+ 2830.1,
34+ 2818.3
35+ ],
19 "throughput": [36 "throughput": [
20 35.0,37 35.0,
21 129.3,38 129.3,
@@ -23,7 +23,7 @@ def transfer_logs_as_json(log_file, output_json_file):
23 """23 """
24 24 
25 log_pattern = re.compile(25 log_pattern = re.compile(
26- r"throughput per GPU \(TFLOP/s/GPU\):\s+([0-9.]+)\s+\|.*?lm loss:\s+([0-9.]+E[+-][0-9]+) | .* actor/pg_loss : ([0-9.]+)"26+ r"elapsed time per iteration \(ms\):\s+([0-9.]+)\s+\| throughput per GPU \(TFLOP/s/GPU\):\s+([0-9.]+)\s+\| .*?lm loss:\s+([0-9.]+E[+-][0-9]+) | .* actor/pg_loss : ([0-9.]+)"
27 )27 )
28 28 
29 if "trl_ppo" in log_file:29 if "trl_ppo" in log_file:
@@ -37,8 +37,10 @@ def transfer_logs_as_json(log_file, output_json_file):
37 37 
38 data = {38 data = {
39 "lm loss": [],39 "lm loss": [],
40+ "time info": [],
40 "throughput": [],41 "throughput": [],
41- "memo info": []42+ "memo info": [],
43+
42 }44 }
43 with open(log_file, "r") as f:45 with open(log_file, "r") as f:
44 log_content = f.read()46 log_content = f.read()
@@ -46,9 +48,10 @@ def transfer_logs_as_json(log_file, output_json_file):
46 memory_matches = memory_pattern.findall(log_content)48 memory_matches = memory_pattern.findall(log_content)
47 49 
48 if log_matches:50 if log_matches:
49- if log_matches[0][1] != "":51+ if log_matches[0][1][2] != "":
50- data["lm loss"] = [float(match[1]) for match in log_matches]52+ data["lm loss"] = [float(match[2]) for match in log_matches]
51- data["throughput"] = [float(match[0]) for match in log_matches]53+ data["time info"] = [float(match[0]) for match in log_matches]
54+ data["throughput"] = [float(match[1]) for match in log_matches]
52 else:55 else:
53 data["lm loss"] = [float(match[2]) for match in log_matches]56 data["lm loss"] = [float(match[2]) for match in log_matches]
54 57 
@@ -1,3 +1,4 @@
1+import warnings
1import pytest2import pytest
2from mindspeed_llm import megatron_adaptor3from mindspeed_llm import megatron_adaptor
3from tests.test_tools.acquire_json import transfer_logs_as_json, read_json4from tests.test_tools.acquire_json import transfer_logs_as_json, read_json
@@ -5,6 +6,7 @@ from tests.test_tools.acquire_json import transfer_logs_as_json, read_json
5MEMO_INFO = "memo info"6MEMO_INFO = "memo info"
6THROUGHPUT = "throughput"7THROUGHPUT = "throughput"
7LOSS = "lm loss"8LOSS = "lm loss"
9+TIME_INFO = "time info"
8 10 
9WARM_UP = 511WARM_UP = 5
10 12 
@@ -14,12 +16,14 @@ class TestMargin:
14 loss = 0.0216 loss = 0.02
15 memory = 0.117 memory = 0.1
16 throughput = 0.0518 throughput = 0.05
19+ time = 0.05
17 20 
18 @classmethod21 @classmethod
19 def refresh_margin_from_json(cls, json_obj):22 def refresh_margin_from_json(cls, json_obj):
20 cls.loss = json_obj.get(LOSS + cls._MARGIN_NAME, cls.loss)23 cls.loss = json_obj.get(LOSS + cls._MARGIN_NAME, cls.loss)
21 cls.memory = json_obj.get(MEMO_INFO + cls._MARGIN_NAME, cls.memory)24 cls.memory = json_obj.get(MEMO_INFO + cls._MARGIN_NAME, cls.memory)
22 cls.throughput = json_obj.get(THROUGHPUT + cls._MARGIN_NAME, cls.throughput)25 cls.throughput = json_obj.get(THROUGHPUT + cls._MARGIN_NAME, cls.throughput)
26+ cls.time = json_obj.get(TIME_INFO + cls._MARGIN_NAME, cls.time)
23 27 
24 28 
25class TestCIST:29class TestCIST:
@@ -27,6 +31,7 @@ class TestCIST:
27 margin_loss = 0.02 31 margin_loss = 0.02
28 margin_throughput_percent = 0.0532 margin_throughput_percent = 0.05
29 margin_memory_percent = 0.133 margin_memory_percent = 0.1
34+ margin_time_percent = 0.05
30 35 
31 def _get_baseline(self, baseline_json):36 def _get_baseline(self, baseline_json):
32 # acquire expected results37 # acquire expected results
@@ -46,14 +51,26 @@ class TestCIST:
46 test_obj: the object we want to test compare.51 test_obj: the object we want to test compare.
47 test_type: deterministic or approximate, default is None.52 test_type: deterministic or approximate, default is None.
48 53 
49- Here we temperally test `lm loss`, 'throughput' and `allocated memory`54+ Here we temperally test `lm loss`, 'throughput' , `allocated memory` and `elapsed time per iteration`
50 """55 """
51- comparison_selection = {56+ comparison_base = {
52 LOSS: self._compare_lm_loss,57 LOSS: self._compare_lm_loss,
53- THROUGHPUT: self._compare_throughput,58+ MEMO_INFO: self._compare_memory,
54- MEMO_INFO: self._compare_memory
55 }59 }
56 60
61+ comparison_throughput = {
62+ THROUGHPUT: self._compare_throughput,
63+ }
64+
65+ comparison_time = {
66+ TIME_INFO: self._compare_time,
67+ }
68+
69+ if "time info" in self.expected:
70+ comparison_selection = {**comparison_base, **comparison_time}
71+ else:
72+ comparison_selection = {**comparison_base, **comparison_throughput}
73+
57 if test_obj in comparison_selection:74 if test_obj in comparison_selection:
58 expected_list = self.expected[test_obj]75 expected_list = self.expected[test_obj]
59 if not expected_list:76 if not expected_list:
@@ -73,7 +90,7 @@ class TestCIST:
73 compare_func = comparison_selection[test_obj]90 compare_func = comparison_selection[test_obj]
74 compare_func(expected_list, actual_list)91 compare_func(expected_list, actual_list)
75 else:92 else:
76- raise ValueError(f"Unsupported test object: {test_obj}")93+ warnings.warn(f"The metric of {test_obj} is not selected and will be skipped.", RuntimeWarning, stacklevel=2)
77 94
78 def _compare_lm_loss(self, expected_list, actual_list):95 def _compare_lm_loss(self, expected_list, actual_list):
79 # Because "deterministic computation" affects the throughput, so we just test96 # Because "deterministic computation" affects the throughput, so we just test
@@ -94,6 +111,18 @@ class TestCIST:
94 assert actual_avg_throughput >= expected_avg_throughput or \111 assert actual_avg_throughput >= expected_avg_throughput or \
95 abs(actual_avg_throughput - expected_avg_throughput) / expected_avg_throughput <= TestMargin.throughput, \112 abs(actual_avg_throughput - expected_avg_throughput) / expected_avg_throughput <= TestMargin.throughput, \
96 f"The actual avg throughput {actual_avg_throughput} degradate expected avg throughput {expected_avg_throughput}"113 f"The actual avg throughput {actual_avg_throughput} degradate expected avg throughput {expected_avg_throughput}"
114+
115+ def _compare_time(self, expected_list, actual_list):
116+ try:
117+ expected_avg_time = sum(expected_list[WARM_UP:]) / (len(expected_list) - WARM_UP)
118+ actual_avg_time = sum(actual_list[WARM_UP:]) / (len(actual_list) - WARM_UP)
119+ except:
120+ raise ZeroDivisionError
121+
122+ assert actual_avg_time <= expected_avg_time or \
123+ abs(actual_avg_time - expected_avg_time) / expected_avg_time <= TestMargin.time, \
124+ f"The actual avg time ({actual_avg_time} ms) was {exceed_percentage:.1f}% slower than the expected ({expected_avg_time} ms)."
125+ 
97 126 
98 def _compare_memory(self, expected_list, actual_list):127 def _compare_memory(self, expected_list, actual_list):
99 for i, (expected_val, actual_val) in enumerate(zip(expected_list, actual_list)):128 for i, (expected_val, actual_val) in enumerate(zip(expected_list, actual_list)):
@@ -115,6 +144,11 @@ class TestCIST:
115 self._get_baseline(baseline_json)144 self._get_baseline(baseline_json)
116 self._get_actual(generate_log, generate_json)145 self._get_actual(generate_log, generate_json)
117 self._test_helper("throughput")146 self._test_helper("throughput")
147+
148+ def test_time(self, baseline_json, generate_log, generate_json):
149+ self._get_baseline(baseline_json)
150+ self._get_actual(generate_log, generate_json)
151+ self._test_helper("time info")
118 152 
119 def test_allocated_memory(self, baseline_json, generate_log, generate_json):153 def test_allocated_memory(self, baseline_json, generate_log, generate_json):
120 self._get_baseline(baseline_json)154 self._get_baseline(baseline_json)