A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 4, 17:30 UTC
[Platform] Fix RISC-V platform detection (lscpu parsing + non-NUMA meminfo) (#40427)
Signed-off-by: liuyudong <liuyudong@iscas.ac.cn>
lyd1992 committed
Apr 24, 2026 at 12:33 UTC
100c7b65e7579c8caf4ee0b04a6410b2796b905c
3 files changed
+37
-8
setup.py
+3
-1
@@ -927,7 +927,9 @@ def get_vllm_version() -> str:
927
elif _is_tpu():
928
version += f"{sep}tpu"
929
elif _is_cpu():
930
- if envs.VLLM_TARGET_DEVICE == "cpu":
930
+ # Check the local VLLM_TARGET_DEVICE (may be set by auto-detect above),
931
+ # not envs.VLLM_TARGET_DEVICE, so CPU-only hosts still get `+cpu`.
932
+ if VLLM_TARGET_DEVICE == "cpu":
933
version += f"{sep}cpu"
934
elif _is_xpu():
935
version += f"{sep}xpu"
vllm/platforms/__init__.py
-1
@@ -177,7 +177,6 @@ def cpu_platform_plugin() -> str | None:
177
logger.debug(
178
"Confirmed CPU platform is available because the machine is MacOS."
179
)
180
-
180
except Exception as e:
181
logger.debug("CPU platform is not available because: %s", str(e))
182
vllm/utils/cpu_resource_utils.py
+34
-6
@@ -87,7 +87,13 @@ def get_memory_node_info(node_id: int = 0) -> MemoryNodeInfo:
87
88
meminfo_path = f"/sys/devices/system/node/node{node_id}/meminfo"
89
if not os.path.exists(meminfo_path):
90
- raise RuntimeError(f"{meminfo_path} doesn't exit.")
90
+ # Non-NUMA systems (e.g. many RISC-V boards) don't expose per-node
91
+ # meminfo. Fall back to system-wide numbers from psutil.
92
+ vm = psutil.virtual_memory()
93
+ return MemoryNodeInfo(
94
+ total_memory=vm.total,
95
+ available_memory=vm.available,
96
+ )
97
98
meminfo = {}
99
with open(meminfo_path) as f:
@@ -147,19 +153,36 @@ def get_visible_memory_node() -> list[int]:
153
154
155
@cache
156
+def _synthesize_cpu_list() -> list[LogicalCPUInfo]:
157
+ """Synthesize a flat CPU list: each logical CPU is its own core on
158
+ NUMA node 0. Used when lscpu output is unavailable or unparsable
159
+ (e.g. macOS, RISC-V)."""
160
+ cpu_count = os.cpu_count()
161
+ assert cpu_count
162
+ return [LogicalCPUInfo(i, i, 0) for i in range(cpu_count)]
163
+
164
+
165
def _get_cpu_list() -> list[LogicalCPUInfo]:
166
if platform.system() == "Darwin":
167
# For MacOS, no user-level CPU affinity and SMT, return all CPUs
153
- cpu_count = os.cpu_count()
154
- assert cpu_count
155
- return [LogicalCPUInfo(i, i, 0) for i in range(cpu_count)]
168
+ return _synthesize_cpu_list()
169
170
lscpu_output = subprocess.check_output(
171
"lscpu --json --extended=CPU,CORE,NODE --online", shell=True, text=True
172
)
173
161
- # For platform without NUMA, replace '-' to '0'
162
- lscpu_output = re.sub(r'"node":\s*-\s*(,|\n)', r'"node": 0\1', lscpu_output)
174
+ # For platforms without NUMA, map bare `-` node to 0 so non-NUMA
175
+ # systems keep the existing behavior from #39781.
176
+ lscpu_output = re.sub(r'"node":\s*-\s*(,|\n|\})', r'"node": 0\1', lscpu_output)
177
+
178
+ # On some architectures (notably RISC-V), lscpu also emits bare `-`
179
+ # for cpu/core. Quote them so the JSON parses; they will decode to
180
+ # -1 and be filtered out below, triggering the synthesized fallback.
181
+ lscpu_output = re.sub(
182
+ r'("(?:cpu|core)":\s*)-\s*(,|\n|\})',
183
+ r'\1"-"\2',
184
+ lscpu_output,
185
+ )
186
187
logical_cpu_list: list[LogicalCPUInfo] = json.loads(
188
lscpu_output, object_hook=LogicalCPUInfo.json_decoder
@@ -170,4 +193,9 @@ def _get_cpu_list() -> list[LogicalCPUInfo]:
193
x for x in logical_cpu_list if -1 not in (x.id, x.physical_core, x.numa_node)
194
]
195
196
+ # If lscpu returned no valid entries (e.g. RISC-V where all fields
197
+ # are bare `-`), fall back to synthesized topology.
198
+ if not logical_cpu_list:
199
+ logical_cpu_list = _synthesize_cpu_list()
200
+
201
return logical_cpu_list