Fix cpuinfo init on Linux without CPU sysfs lists (#28230)
### Description
Fixes ONNX Runtime startup on Linux ARM64 environments where
`/sys/devices/system/cpu/possible` and `/sys/devices/system/cpu/present`
are unavailable, such as AWS Lambda ARM64/Graviton and restricted build
sandboxes.
There are two related failure modes:
1. `PosixEnv` may be constructed before ORT's default logger is
registered. If `cpuinfo_initialize()` fails during that early
construction path, the existing `LOGS_DEFAULT(INFO)` call can terminate
with `Attempt to use DefaultLogger but none has been registered`.
2. The bundled `pytorch/cpuinfo` code treats missing Linux CPU
`possible`/`present` sysfs cpulists as fatal on ARM Linux. The max-count
helpers return `UINT32_MAX`, which wraps to `0` after `1 + UINT32_MAX`
in ARM Linux initialization and prevents cpuinfo from reaching the later
`/proc/cpuinfo` and `getauxval()` based detection paths.
### Root Cause
The immediate import crash is caused by unsafe early logging in
`onnxruntime/core/platform/posix/env.cc`. Python bindings can reference
`Env::Default()` during module load before logging is initialized, so a
cpuinfo initialization failure must not use `LOGS_DEFAULT()` unless a
default logger exists.
The cpuinfo initialization failure is more subtle. A count-only fallback
is not enough: after cpuinfo computes max possible/present CPU counts,
it calls `cpuinfo_linux_detect_possible_processors()` and
`cpuinfo_linux_detect_present_processors()` to set
`CPUINFO_LINUX_FLAG_POSSIBLE` and `CPUINFO_LINUX_FLAG_PRESENT` on each
processor. ARM Linux initialization later marks processors valid only if
those flags are set. If only the count fallback is provided,
`valid_processors` can remain zero and cpuinfo can proceed into an
invalid partial initialization state.
### Fix
- Make `PosixEnv` logging safe when cpuinfo initialization fails before
a default logger exists:
- use `logging::LoggingManager::HasDefaultLogger()` before
`LOGS_DEFAULT()`
- fall back to `std::cerr` when no logger is registered
- Add a cpuinfo patch for Linux missing sysfs CPU cpulists:
- fallback max possible/present processor detection to
`sysconf(_SC_NPROCESSORS_ONLN) - 1`
- fallback present/possible processor flag detection by marking CPUs
`0..nproc-1`
- preserve existing sysfs parsing behavior when the cpulist files are
available
- Wire the cpuinfo patch into the existing cpuinfo FetchContent flow for
Linux and existing ARM64/ARM64EC patch path.
- Add a simulation test that validates:
- safe early logging without a registered default logger
- `sysconf(_SC_NPROCESSORS_ONLN)` count and present/possible flag
fallback behavior
- hiding `/sys/devices/system/cpu/{possible,present}` via `LD_PRELOAD`
- optional ORT import with hidden sysfs when a built ORT package is
importable
### Testing
Ran from a clean branch/worktree:
```bash
python onnxruntime/test/common/test_cpuinfo_sysfs_fallback.py
```
Result:
- safe logging simulation: PASS
- sysconf count + flag fallback simulation: PASS
- LD_PRELOAD sysfs-hiding simulation: PASS
- ORT import integration: SKIP (`onnxruntime.capi` not built/importable
in this workspace)
Also validated the cpuinfo patch directly:
```bash
cd build/cu128/Release/_deps/pytorch_cpuinfo-src
patch --dry-run -p1 < /path/to/cmake/patches/cpuinfo/fix_missing_sysfs_fallback.patch
```
And syntax-checked patched `src/linux/processors.c` in a temporary tree
with cpuinfo headers.
### Related Issue
Fixes #10038.