已合并
add test for TORCH_ACL_INIT_CONFIG_PATH #39953
huangyunlong创建于 7月3日
add test for TORCH_ACL_INIT_CONFIG_PATH #39953
已合并
huangyunlong创建于 7月3日
2 个文件变更+145-9
Mtest/npu/test_option.py+133-3
@@ -1,13 +1,14 @@
1+import os
1import sys2import sys
2import subprocess3import subprocess
4+import unittest
5+from functools import wraps
3 6 
4import torch7import torch
5import torch_npu8import torch_npu
6 9 
7-import torch_npu.npu.utils as utils
8- 
9from torch_npu.testing.testcase import TestCase, run_tests10from torch_npu.testing.testcase import TestCase, run_tests
10-from torch_npu.testing.common_utils import SupportedDevices11+from torch_npu.testing.common_utils import SupportedDevices, SkipIfNotGteCANNVersion
11 12 
12 13 
13class TestOption(TestCase):14class TestOption(TestCase):
@@ -111,5 +112,134 @@ class TestAclOpInitMode(TestCase):
111 self.assertIn(self.INVALID_VALUE_WARN, stderr)112 self.assertIn(self.INVALID_VALUE_WARN, stderr)
112 113 
113 114 
115+def _skipIfLazy(fn):
116+ @wraps(fn)
117+ def wrapper(slf, *args, **kwargs):
118+ if torch_npu.npu.utils._is_gte_cann_version('8.3.RC1'):
119+ raise unittest.SkipTest(
120+ "Test only for non-lazy set_device mode (CANN < 8.3.RC1)")
121+ return fn(slf, *args, **kwargs)
122+ return wrapper
123+ 
124+ 
125+class TestAclInitConfigPath(TestCase):
126+ 
127+ LACKS_DEFAULT_DEVICE_MSG = "lacks 'defaultDevice'"
128+ HAS_DEFAULT_DEVICE_MSG = "contains 'defaultDevice'"
129+ PARSE_FAILED_MSG = "Failed to parse user acl json"
130+ INVALID_PATH_MSG = "is invalid"
131+ OPEN_FAILED_MSG = "Failed to open user acl json"
132+ 
133+ def _make_temp_json(self, content):
134+ import tempfile
135+ tmp = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False)
136+ tmp.write(content)
137+ tmp.close()
138+ self.addCleanup(os.unlink, tmp.name)
139+ return tmp.name
140+ 
141+ def _run_with_env(self, json_path):
142+ test_script = (
143+ f"import os; "
144+ f"os.environ['TORCH_ACL_INIT_CONFIG_PATH']='{json_path}'; "
145+ f"import torch; import torch_npu; torch_npu.npu.set_device(0)"
146+ )
147+ result = subprocess.run(
148+ [sys.executable, '-c', test_script],
149+ capture_output=True, text=True
150+ )
151+ return result
152+ 
153+ # ---- 设备无关:路径无效/解析失败 ----
154+ 
155+ def test_invalid_json(self):
156+ """非法 JSON 格式应抛 RuntimeError"""
157+ json_path = self._make_temp_json('not a json{{{')
158+ ret = self._run_with_env(json_path)
159+ self.assertNotEqual(ret.returncode, 0)
160+ self.assertIn(self.PARSE_FAILED_MSG, ret.stderr,
161+ "Invalid JSON should raise RuntimeError")
162+ 
163+ def test_nonexistent_path(self):
164+ """不存在的路径应抛 RuntimeError"""
165+ json_path = '/tmp/nonexistent_acl_config_for_test.json'
166+ ret = self._run_with_env(json_path)
167+ self.assertNotEqual(ret.returncode, 0)
168+ self.assertIn(self.INVALID_PATH_MSG, ret.stderr,
169+ "Non-existent path should raise RuntimeError")
170+ 
171+ def test_empty_json_file(self):
172+ """空 JSON 文件应抛 RuntimeError"""
173+ json_path = self._make_temp_json('')
174+ ret = self._run_with_env(json_path)
175+ self.assertNotEqual(ret.returncode, 0)
176+ self.assertIn(self.PARSE_FAILED_MSG, ret.stderr,
177+ "Empty JSON file should raise RuntimeError")
178+ 
179+ # ---- non-lazy 模式(CANN < 8.3.RC1) ----
180+ 
181+ @_skipIfLazy
182+ def test_valid_json_non_lazy(self):
183+ """non-lazy 模式:不含 defaultDevice 的用户 JSON 正常使用"""
184+ json_path = self._make_temp_json('{"dump":{"dump_scene":"lite_exception"}}')
185+ ret = self._run_with_env(json_path)
186+ self.assertEqual(ret.returncode, 0,
187+ f"Valid JSON in non-lazy should succeed, got: {ret.stderr}")
188+ 
189+ @_skipIfLazy
190+ def test_valid_json_with_default_device_in_non_lazy(self):
191+ """non-lazy 模式:含 defaultDevice 应抛 RuntimeError"""
192+ json_path = self._make_temp_json(
193+ '{"dump":{"dump_scene":"lite_exception"},"defaultDevice":{"default_device":"0"}}'
194+ )
195+ ret = self._run_with_env(json_path)
196+ self.assertNotEqual(ret.returncode, 0)
197+ self.assertIn(self.HAS_DEFAULT_DEVICE_MSG, ret.stderr,
198+ "Non-lazy mode with defaultDevice should raise RuntimeError")
199+ 
200+ # ---- lazy 模式(CANN >= 8.3.RC1) ----
201+ 
202+ @SkipIfNotGteCANNVersion('8.3.RC1')
203+ def test_valid_json_with_default_device_in_lazy(self):
204+ """lazy 模式:含合法 defaultDevice 正常使用"""
205+ json_path = self._make_temp_json(
206+ '{"dump":{"dump_scene":"lite_exception"},"defaultDevice":{"default_device":"0"}}'
207+ )
208+ ret = self._run_with_env(json_path)
209+ self.assertEqual(ret.returncode, 0,
210+ f"Valid JSON in lazy should succeed, got: {ret.stderr}")
211+ 
212+ @SkipIfNotGteCANNVersion('8.3.RC1')
213+ def test_json_without_default_device_in_lazy(self):
214+ """lazy 模式:不含 defaultDevice 应抛 RuntimeError"""
215+ json_path = self._make_temp_json('{"dump":{"dump_scene":"lite_exception"}}')
216+ ret = self._run_with_env(json_path)
217+ self.assertNotEqual(ret.returncode, 0)
218+ self.assertIn(self.LACKS_DEFAULT_DEVICE_MSG, ret.stderr,
219+ "Lazy mode without defaultDevice should raise RuntimeError")
220+ 
221+ @SkipIfNotGteCANNVersion('8.3.RC1')
222+ def test_json_wrong_default_device_value_in_lazy(self):
223+ """lazy 模式:default_device 值不为 '0' 应抛 RuntimeError"""
224+ json_path = self._make_temp_json(
225+ '{"defaultDevice":{"default_device":"1"}}'
226+ )
227+ ret = self._run_with_env(json_path)
228+ self.assertNotEqual(ret.returncode, 0)
229+ self.assertIn('requires', ret.stderr,
230+ "default_device='1' should raise RuntimeError")
231+ 
232+ @SkipIfNotGteCANNVersion('8.3.RC1')
233+ def test_json_default_device_wrong_type(self):
234+ """lazy 模式:defaultDevice 非 object 应抛 RuntimeError"""
235+ json_path = self._make_temp_json(
236+ '{"defaultDevice":"not_an_object","dump":{"dump_scene":"lite_exception"}}'
237+ )
238+ ret = self._run_with_env(json_path)
239+ self.assertNotEqual(ret.returncode, 0)
240+ self.assertIn(self.LACKS_DEFAULT_DEVICE_MSG, ret.stderr,
241+ "defaultDevice as string should raise RuntimeError")
242+ 
243+ 
114if __name__ == "__main__":244if __name__ == "__main__":
115 run_tests()245 run_tests()
Mtorch_npu/csrc/core/npu/sys_ctrl/npu_sys_ctrl.cpp+12-6
@@ -116,13 +116,15 @@ std::string GetAclConfigJsonPath()
116 std::string json_path = std::string(acl_init_path);116 std::string json_path = std::string(acl_init_path);
117 std::string json_path_str = torch_npu::toolkit::profiler::Utils::RealPath(json_path);117 std::string json_path_str = torch_npu::toolkit::profiler::Utils::RealPath(json_path);
118 if (json_path_str.empty()) {118 if (json_path_str.empty()) {
119- TORCH_CHECK(false, "TORCH_ACL_INIT_CONFIG_PATH ", acl_init_path,119+ TORCH_CHECK(false, "TORCH_ACL_INIT_CONFIG_PATH ", acl_init_path, " is invalid. ",
120- " is invalid.", PTA_ERROR(ErrCode::UNAVAIL));120+ "Please set the environment variable 'TORCH_ACL_INIT_CONFIG_PATH' to a valid JSON config file path.",
121+ PTA_ERROR(ErrCode::UNAVAIL));
121 }122 }
122 123 
123 std::ifstream config_file(json_path_str);124 std::ifstream config_file(json_path_str);
124 if (!config_file.is_open()) {125 if (!config_file.is_open()) {
125 TORCH_CHECK(false, "Failed to open user acl json ", json_path_str,126 TORCH_CHECK(false, "Failed to open user acl json ", json_path_str,
127+ ". Please ensure the file exists and has read permission.",
126 PTA_ERROR(ErrCode::UNAVAIL));128 PTA_ERROR(ErrCode::UNAVAIL));
127 }129 }
128 130 
@@ -132,13 +134,15 @@ std::string GetAclConfigJsonPath()
132 config_file >> config;134 config_file >> config;
133 } catch (const std::exception& e) {135 } catch (const std::exception& e) {
134 TORCH_CHECK(false, "Failed to parse user acl json ", json_path_str,136 TORCH_CHECK(false, "Failed to parse user acl json ", json_path_str,
135- " : ", e.what(), PTA_ERROR(ErrCode::UNAVAIL));137+ ". Please check that the file contains valid JSON syntax. Error: ", e.what(),
138+ PTA_ERROR(ErrCode::UNAVAIL));
136 }139 }
137 140 
138 if (c10_npu::is_lazy_set_device()) {141 if (c10_npu::is_lazy_set_device()) {
139 if (!config.contains("defaultDevice") || !config["defaultDevice"].is_object()) {142 if (!config.contains("defaultDevice") || !config["defaultDevice"].is_object()) {
140 TORCH_CHECK(false, "User acl json ", json_path_str,143 TORCH_CHECK(false, "User acl json ", json_path_str,
141- " lacks 'defaultDevice' object, required for lazy set_device mode.",144+ " lacks 'defaultDevice' object, required for lazy set_device mode. ",
145+ "Please add: \"defaultDevice\": {\"default_device\": \"0\"}",
142 PTA_ERROR(ErrCode::VALUE));146 PTA_ERROR(ErrCode::VALUE));
143 }147 }
144 const auto& default_dev = config["defaultDevice"];148 const auto& default_dev = config["defaultDevice"];
@@ -146,13 +150,15 @@ std::string GetAclConfigJsonPath()
146 !default_dev["default_device"].is_string() ||150 !default_dev["default_device"].is_string() ||
147 default_dev["default_device"].get<std::string>() != "0") {151 default_dev["default_device"].get<std::string>() != "0") {
148 TORCH_CHECK(false, "User acl json ", json_path_str,152 TORCH_CHECK(false, "User acl json ", json_path_str,
149- " requires 'defaultDevice.default_device' to be \"0\" in lazy set_device mode.",153+ " requires 'defaultDevice.default_device' to be \"0\" in lazy set_device mode. ",
154+ "Please set: \"defaultDevice\": {\"default_device\": \"0\"}",
150 PTA_ERROR(ErrCode::VALUE));155 PTA_ERROR(ErrCode::VALUE));
151 }156 }
152 } else {157 } else {
153 if (config.contains("defaultDevice")) {158 if (config.contains("defaultDevice")) {
154 TORCH_CHECK(false, "User acl json ", json_path_str,159 TORCH_CHECK(false, "User acl json ", json_path_str,
155- " contains 'defaultDevice' which is not expected in non-lazy set_device mode.",160+ " contains 'defaultDevice' which is not expected in non-lazy set_device mode. ",
161+ "Please remove the 'defaultDevice' field from your JSON config.",
156 PTA_ERROR(ErrCode::VALUE));162 PTA_ERROR(ErrCode::VALUE));
157 }163 }
158 }164 }