Add --test_parallel to reduce CTest concurrency for ASan builds (#28675)
## Description
The `windows_x64_asan / build_x64` CI pipeline has been failing with OOM
(out-of-memory) because ASan-instrumented test binaries consume
significantly more memory than normal builds, and CTest was running them
at full CPU-count parallelism.
This PR adds a `--test_parallel` argument to `build.py` that allows
CTest concurrency to be configured independently from the build
parallelism (`--parallel`). It then uses `--test_parallel 4` in the
Windows x64 ASan workflow to cap test execution to 4 parallel jobs,
preventing OOM while keeping build parallelism at full speed.
## Motivation and Context
- ASan instrumentation inflates per-process memory usage by ~2-3x.
- The existing `--parallel` flag controls both MSBuild and CTest
concurrency together; there was no way to keep fast parallel builds
while limiting test concurrency.
- The CI runner has limited memory, and running all tests in parallel
under ASan exceeded available RAM.
## Changes
| File | Change |
|------|--------|
| `tools/ci_build/build_args.py` | Add `--test_parallel` argument
(default: `None`, falls back to `--parallel`) |
| `tools/ci_build/build.py` | Add `number_of_test_parallel_jobs()`
helper; use it for CTest `--parallel`; validate negative values |
| `.github/workflows/windows_build_x64_asan.yml` | Pass `--test_parallel
4` to cap ASan test concurrency |
## Testing
- `python -m py_compile tools/ci_build/build.py
tools/ci_build/build_args.py` — passes
- `python tools/ci_build/build.py --help` shows the new
`--test_parallel` option
- `git diff --check` — no whitespace issues
- When `--test_parallel` is omitted, behavior is unchanged (falls back
to `--parallel` value)