Skip to content

add cpuList#1417

Merged
alexcos20 merged 2 commits into
next-4from
feature/cpuList_for_docker
Jul 14, 2026
Merged

add cpuList#1417
alexcos20 merged 2 commits into
next-4from
feature/cpuList_for_docker

Conversation

@alexcos20

Copy link
Copy Markdown
Member

Fixes #1414

Feature: cpuList — restrict C2D CPU pinning to an explicit set of host cores

Summary

The Docker C2D engine pins compute containers to physical cores (CpusetCpus), but the
core pool was always [0 .. NCPU-1], taken from docker.info(), and
allocateCpus() always hands out the lowest-numbered free cores tracked in the
node's own in-memory allocation map. Consequently:

  • the configured cpu total only capped how much CPU could be allocated concurrently,
    never which core IDs were used — jobs always gravitated to the low-numbered cores;
  • an operator had no way to keep the engine off specific cores (e.g. reserve cores for
    the OS / other workloads, or partition the cores of a shared host between
    independently-managed engines, which otherwise all pin to the same low cores).

This PR adds an explicit cpuList option on the connection-level cpu resource in
DOCKER_COMPUTE_ENVIRONMENTS, restricting the pinning pool to exactly the listed host
core IDs.

[
  {
    "socketPath": "/var/run/docker.sock",
    "resources": [{ "id": "cpu", "cpuList": "32-63" }],
    "environments": [ ... ]
  }
]

What changed

  • src/@types/C2D/C2D.tsComputeResource gains optional cpuList?: string.
  • src/utils/config/schemas.ts
    • ComputeResourceSchema accepts cpuList and validates it strictly (see rules
      below) via superRefine, with a dedicated error message per violation.
    • C2DDockerConfigSchema enforces that a connection-level cpu entry specifies
      exactly one of total / cpuList (both → error, neither → error), and rejects
      cpuList on non-cpu resources and inside env-level resource refs (same clean-break
      treatment as init/driverVersion).
    • Any violation fails config validation at startup: the node prints the
      ❌ Invalid Ocean Node configuration issue list and exits (existing
      builder.ts behavior — no new exit logic).
  • src/components/c2d/compute_engine_docker.ts
    • New resolveConfiguredCpuList(): expands the (schema-validated) ranges at engine
      start and checks them against the host's NCPU. If any core ID doesn't exist on the
      host, the engine logs an error and refuses to start (no envs created) instead of
      silently pinning elsewhere.
    • The shared per-environment core pool becomes the expanded cpuList when configured
      (previously always [0 .. NCPU-1]). allocateCpus() therefore only ever hands out
      listed cores; requests beyond the pool still return null rather than spilling to
      unlisted cores.
    • With cpuList, the effective cpu total (and max cap) is the number of listed
      cores, so resource matching can never admit more CPU than the pinning pool holds.
    • No changes to allocation/release/recovery logic itself — job containers, service
      containers, and restart recovery all consume the same pool/CpusetCpus paths.
  • docs/env.mdcpuList documented under the connection-level resources
    fields of DOCKER_COMPUTE_ENVIRONMENTS.

cpuList validation rules

Format is deliberately strict; every violation is a startup error with its own message:

  • Comma-separated core IDs and/or integer ranges: "0", "3,5,7", "0-1,3",
    "0-15,32-47". A bare ID covers the single-cpu case ("0") and picking individual
    cores.
  • Floats, negative values, signs, spaces, empty parts and trailing commas are rejected.
  • A range's right side must be strictly greater than its left side
    ("15-15", "20-10" → rejected; write a single core as a bare ID instead).
  • All parts must be ascending and non-overlapping ("0-8,4-12", "8-11,0-3",
    "0-3,2", "3,3" → rejected).
  • Mutually exclusive with total; the cpu entry must specify exactly one of the two.
  • Every listed core ID must exist on the host (checked against docker.info().NCPU at
    engine start; out-of-range IDs → engine is skipped with an explicit error).

Omitting cpuList keeps the current behavior (full host core range, total semantics
unchanged), so existing configs are unaffected.

Tests

  • 32 new unit tests in src/test/unit/compute.test.ts:
    • Schema: valid configs accepted — single range, multiple ranges, bare core IDs
      ("0", "3,5,7"), mixed ("0-1,3"), and total-only (regression);
      both/neither total+cpuList rejected; cpuList on non-cpu resources and in
      env-level refs rejected; 12 malformed/semantic cases rejected with the expected
      message each.
    • Engine: resolveConfiguredCpuList() expansion (single range, multi-range,
      mixed ranges + bare IDs, single-cpu host "0"), unrestricted default (null
      pool), out-of-range abort; resolveConnectionResourcePool() derives effective cpu
      total from the list length; allocateCpus() only hands out listed cores, reuses
      released ones, and returns null when the restricted pool is exhausted.
  • Compute unit suite passes 95/95; lint (0 errors) and type-check are clean.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a1fda9d-58d6-48da-bac2-0229238dd7a7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/cpuList_for_docker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@alexcos20 alexcos20 linked an issue Jul 14, 2026 that may be closed by this pull request
@alexcos20

Copy link
Copy Markdown
Member Author

/run-security-scan

@alexcos20 alexcos20 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI automated code review (Gemini 3).

Overall risk: low

Summary:
The PR introduces a robust cpuList configuration feature to pin C2D compute containers to specific host CPU cores. The documentation, schema validation, and unit tests are comprehensive and well-executed. A few minor improvements are recommended, particularly around preventing unintended array mutations and ensuring fail-fast behavior on misconfiguration.

Comments:
• [WARNING][bug] The property this.configuredCpuList is assigned directly to allCores, which is then shared across environments. Since allocateCpus() dynamically assigns and removes free cores from this pool, it will unintentionally mutate the this.configuredCpuList class property. If the class property is read again later, it will yield the currently free cores instead of the configured cores. Consider cloning the array when assigning it to prevent state mutation.

-    const allCores =
-      this.configuredCpuList ?? Array.from({ length: physicalCpuCount }, (_, i) => i)
+    const allCores = this.configuredCpuList
+      ? [...this.configuredCpuList]
+      : Array.from({ length: physicalCpuCount }, (_, i) => i)

• [INFO][other] Currently, returning false from resolveConfiguredCpuList causes updateEnvironmentResources to silently abort initialization, potentially leaving the engine in a broken, uninitialized state. Unless graceful degradation is explicitly desired by the calling code, consider throwing an Error to fail fast and explicitly prevent the node from starting with an invalid configuration.

-    if (!this.resolveConfiguredCpuList(envConfig, sysinfo.NCPU)) {
-      return
-    }
+    if (!this.resolveConfiguredCpuList(envConfig, sysinfo.NCPU)) {
+      throw new Error(`Failed to initialize C2D engine: invalid cpuList configuration.`)
+    }

• [INFO][security] While Number.isSafeInteger prevents overflow, it allows huge ranges (e.g., 0-9999999). If parseCpusetString expands this into an array in memory, it could cause an Out-Of-Memory (OOM) crash (Denial of Service). Assuming cpuList is only set by trusted node operators, this risk is low, but enforcing a realistic physical core limit (e.g., 8192) adds a good layer of defense.

      if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end)) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `cpuList range "${part}": core IDs are too large to be valid CPU IDs`,
          path
        })
        continue
      }
+     if (end > 8192) {
+       ctx.addIssue({
+         code: z.ZodIssueCode.custom,
+         message: `cpuList range "${part}": core ID exceeds maximum supported limit`,
+         path
+       })
+     }

• [INFO][style] Excellent test coverage! The unit tests cover edge cases (e.g., out-of-order, duplicates, floats, overlaps) comprehensively. LGTM!

@alexcos20

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@alexcos20

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your plan includes PR reviews subject to rate limits. More reviews will be available in 42 minutes.

@alexcos20 alexcos20 merged commit 7bcf7f0 into next-4 Jul 14, 2026
19 of 20 checks passed
@alexcos20 alexcos20 deleted the feature/cpuList_for_docker branch July 14, 2026 07:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Prefix for cpu pinning

2 participants