Skip to content

E2E: Minor fixes to Memory Manager and hugepages split tests - #1578

Open
mrniranjan wants to merge 2 commits into
openshift:mainfrom
mrniranjan:fix_mm_hugepages
Open

E2E: Minor fixes to Memory Manager and hugepages split tests#1578
mrniranjan wants to merge 2 commits into
openshift:mainfrom
mrniranjan:fix_mm_hugepages

Conversation

@mrniranjan

@mrniranjan mrniranjan commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
  1. updating_profile: preserve existing reserved/isolated CPUs

Hardcoding isolated=1-2 and reserved=0,3 on large-CPU nodes inflated tuned.non_isolcpus and systemd.cpu_affinity, which could drop later cmdline args such as hugepages and break test_id:34081. Keep the profile's CPU set and assert isolcpus, affinity, and ReservedSystemCPUs against those values instead.

  1. E2E: memorymanager: pin hugepages per NUMA for TopologyAffinityError tests

The restricted and single-numa-node fixtures assumed that configuring 20 x 2Mi hugepages without a NUMA Node would split evenly across both NUMA nodes (10/10). That is not how cmdline hugepages=N works: the
kernel places pages system-wide, and Memory Manager can see an uneven split (for example 24Mi on NUMA 0 and 16Mi on NUMA 1). With 24Mi free on one node, a Guaranteed pod requesting 24Mi hugepages + 2 CPUs was admitted instead of failing with TopologyAffinityError.

Pin 10 x 2Mi hugepages on each NUMA node so each zone has only 20Mi, restoring the rejection expectation. Also DeferCleanup test pods so flake retries do not leak hugepages from a failed attempt.

Summary by CodeRabbit

  • Tests
    • Improved validation of hugepage allocation and capacity on each NUMA node.
    • Expanded coverage for NUMA affinity, topology errors, and scheduling failures.
    • Enhanced performance profile update checks to preserve and validate existing reserved and isolated CPU assignments.
    • Added validation for kubelet and system CPU configuration consistency, including OVS-DPDK reservations.
    • Improved resource cleanup between test scenarios.
    • Added coverage for extracting kernel command-line parameters across common formats.

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 6, 2026
@mrniranjan
mrniranjan marked this pull request as draft August 6, 2026 07:40
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Walkthrough

The performance profile tests now allocate hugepages per NUMA node, defer pod cleanup, and preserve existing CPU sets. CPU validation covers kernel command-line, systemd, tuned, topology, and kubelet settings.

Changes

Performance profile test updates

Layer / File(s) Summary
Kernel command-line parameter parser
test/e2e/performanceprofile/functests/utils/nodes/nodes.go, test/e2e/performanceprofile/functests/utils/nodes/nodes_test.go
Adds FindCmdlineParam and table-driven tests for standard, missing, valueless, prefix-matching, hexadecimal, and real kernel command-line parameters.
Preserved CPU configuration validation
test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go
Preserves reserved and isolated CPU sets from the profile. Validates tuned.non_isolcpus, isolcpus, systemd.cpu_affinity, topology settings, and kubelet reservedSystemCPUs.
NUMA-aware hugepage test behavior
test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go
Allocates 10 pinned 2 Mi hugepages on each NUMA node. Updates capacity and topology expectations. Uses deferred pod cleanup while retaining required scheduling and NUMA affinity checks.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: swatisehgal, ffromani


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error New assertions print the complete live /proc/cmdline with %q when parameters are missing; this can expose host identifiers or deployment-specific boot arguments. Log only the node name, parameter key, and sanitized value or expected value; do not include the complete /proc/cmdline in assertion messages.
Test Structure And Quality ⚠️ Warning New validation tests in updating_profile.go contain many bare Expect(err).ToNot(HaveOccurred()) assertions, so failures lack the required operation and node context. Add meaningful messages to each new assertion, including the node name and operation, and use bounded contexts for direct cluster calls where applicable.
Microshift Test Compatibility ⚠️ Warning Four new It tests are unguarded and run in a PerformanceProfile context using the unavailable performance.openshift.io API group; no MicroShift skip or apigroup tag exists. Add [apigroup:performance.openshift.io] or [Skipped:MicroShift], or guard with IsMicroShiftCluster(). Verify with the MicroShift parallel e2e job.
✅ Passed checks (12 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All Ginkgo titles in the changed files are static string literals; added table-test names are also fixed strings, with no pod, node, namespace, timestamp, IP, or generated identifier.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The added Ginkgo tests inspect CPU settings on selected nodes and the modified memory tests use multiple NUMA zones on one target node; no multi-node or HA assumption is introduced.
Topology-Aware Scheduling Compatibility ✅ Passed The PR changes only E2E test code and utilities. It adds no deployment, operator, controller, or topology scheduling constraints.
Ote Binary Stdout Contract ✅ Passed The full two-commit diff adds no stdout or logging calls; suite logging targets os.Stderr, and new setup executes through BeforeEach rather than process-level hooks.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Added Ginkgo checks only read node cmdline and kubelet data; added unit tests parse CPU strings. No IPv4 literals, IP-only parsing, public URLs, or external connectivity found.
No-Weak-Crypto ✅ Passed The two-commit diff adds no MD5, SHA1, DES, RC4, Blowfish, ECB, crypto APIs, custom crypto, or secret/token comparisons.
Container-Privileges ✅ Passed The PR changes only four Go test files; added-line scans found no privileged, hostPID, hostNetwork, hostIPC, SYS_ADMIN, allowPrivilegeEscalation, or explicit root settings.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately identifies the main changes to the Memory Manager and hugepages split E2E tests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@openshift-ci
openshift-ci Bot requested review from ffromani and swatisehgal August 6, 2026 07:41
@qodo-for-rh-openshift

Copy link
Copy Markdown

PR Summary by Qodo

E2E: Stabilize memory manager hugepages/NUMA tests and preserve profile CPU sets

🐞 Bug fix 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Pin 2Mi hugepages per NUMA node to restore deterministic TopologyAffinityError expectations.
• Defer pod cleanup in memory manager tests to avoid hugepages leakage across retries.
• Stop hardcoding reserved/isolated CPUs when updating profiles; assert cmdline/kubelet settings
 against the profile.
Diagram

graph TD
  T(E2E perf tests) --> P["PerformanceProfile CR"] --> M["MCO/Tuned apply"] --> C["Node /proc/cmdline"] --> K["Kubelet + Memory Manager"] --> Pod["Test Pods (hugepages/CPU)"]
  T --> Pod
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Relax assertions to tolerate uneven hugepages split
  • ➕ Avoids per-NUMA hugepages pinning and keeps profile simpler
  • ➖ Weakens the test signal; may miss real regressions in topology enforcement and admission decisions
2. Discover actual NUMA hugepages distribution and compute expected outcome
  • ➕ More robust to platform variance; tests adapt to real node state
  • ➖ More complex test logic; still risks flake if distribution changes during retries or other workloads interfere
3. Configure hugepages via sysfs/node tuning instead of PerformanceProfile HugePages.Node
  • ➕ Directly enforces NUMA placement; closer to kernel mechanics
  • ➖ Moves away from NTO-supported configuration path; higher maintenance and portability risk

Recommendation: Keep the PR’s approach: pin hugepages per NUMA using the supported PerformanceProfile HugePages.Node fields and make cleanup deterministic via DeferCleanup. This restores the intended TopologyAffinityError coverage while preventing resource leakage across flake retries. Preserving reserved/isolated CPUs from the existing profile also avoids unintended cmdline side-effects on large-CPU nodes.

Files changed (2) +129 / -35

Bug fix (1) +76 / -12
updating_profile.goPreserve reserved/isolated CPUs and assert cmdline/kubelet values against profile +76/-12

Preserve reserved/isolated CPUs and assert cmdline/kubelet values against profile

• Stops overwriting CPU reserved/isolated sets with hardcoded small ranges; instead parses and preserves the existing profile CPU sets. Reworks assertions to validate isolcpus and systemd.cpu_affinity based on the preserved sets and validates ReservedSystemCPUs by parsing kubelet config (including optional OvsDpdk CPUs). Adds regex-based extraction for cmdline parameters.

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go

Tests (1) +53 / -23
memorymanager.goPin 2Mi hugepages per NUMA and ensure pod cleanup in MM topology tests +53/-23

Pin 2Mi hugepages per NUMA and ensure pod cleanup in MM topology tests

• Updates restricted and single-numa-node fixtures to allocate 2Mi hugepages with explicit NUMA Node assignments (10 pages per node) to avoid kernel-wide placement skew. Adds DeferCleanup blocks to reliably delete test pods (and free hugepages/CPU allocations) even when tests fail or retry.

test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go`:
- Around line 643-645: Update the DeferCleanup callback around mm1.removePod to
inspect and handle its error instead of discarding it: tolerate only a NotFound
result after the explicit deletion, and fail cleanup for every other error using
the test framework’s established failure mechanism.

In
`@test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go`:
- Around line 324-335: Update the cmdline assertion in the “verify that isolcpus
matches the performance profile” test to match the complete whitespace-delimited
kernel argument rather than using ContainSubstring. Build a regex with
regexp.QuoteMeta(expectedIsol) and boundaries that require whitespace or the
start/end of the command line, while preserving the existing expectedIsol
construction and node iteration.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 53956587-b78f-4abb-8ee9-572f0bafc9e7

📥 Commits

Reviewing files that changed from the base of the PR and between 837ae9f and 4a85eaf.

📒 Files selected for processing (2)
  • test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go
  • test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go

Comment on lines +643 to +645
DeferCleanup(func() {
_ = mm1.removePod(context.TODO(), testPod1)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle unexpected cleanup errors.

Line 644 discards every deletion error. If the test fails before Line 654, a cleanup failure can leave the pod and its NUMA resources allocated for later tests.

Ignore only a NotFound result after the explicit deletion. Fail the cleanup for every other error.

As per path instructions, **/*.go: Never ignore error returns.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go`
around lines 643 - 645, Update the DeferCleanup callback around mm1.removePod to
inspect and handle its error instead of discarding it: tolerate only a NotFound
result after the explicit deletion, and fail cleanup for every other error using
the test framework’s established failure mechanism.

Source: Path instructions

@qodo-for-rh-openshift

qodo-for-rh-openshift Bot commented Aug 6, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Wrong systemd affinity expectation ✓ Resolved 🐞 Bug ≡ Correctness
Description
The test asserts systemd.cpu_affinity equals the Reserved CPUSet, but tuned sets
systemd.cpu_affinity to the complement of isolated CPUs (all non-isolated). This is
incorrect/fragile for valid profiles where Reserved != (online \ isolated), such as Mixed CPUs with
Shared CPUs enabled.
Code

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[R345-348]

+				affinitySet, err := cpuset.Parse(matches[1])
+				Expect(err).ToNot(HaveOccurred())
+				Expect(affinitySet.Equals(expectedReserved)).To(BeTrue(),
+					"systemd.cpu_affinity=%s does not match reserved CPUs %s", affinitySet.String(), expectedReserved.String())
Relevance

●●● Strong

Correctness fix: avoids invalid assumption by matching tuned’s affinity logic; prevents mixed-CPU
false failures.

PR-#1397
PR-#1302

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Tuned defines systemd.cpu_affinity from the inverted isolated set, and Mixed CPUs can introduce
Shared CPUs that are non-isolated but not reserved, making reserved-equality an invalid assumption.

assets/performanceprofile/tuned/openshift-node-performance[32-33]
assets/performanceprofile/tuned/openshift-node-performance[149-150]
test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[338-349]
pkg/performanceprofile/controller/performanceprofile/components/profile/profile.go[95-103]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`systemd.cpu_affinity` is generated by tuned as `${not_isolated_cores_expanded}`, which is computed by inverting `isolated_cores_expanded`—it is **not** sourced from `spec.cpu.reserved`. The test currently compares `systemd.cpu_affinity` to the Reserved CPU set, which can be wrong for profiles that use Shared CPUs (Mixed CPUs) or any configuration where reserved is not the full non-isolated set.

### Issue Context
The tuned profile defines `not_isolated_cores_expanded` as an invert of isolated cores and uses it directly for `systemd.cpu_affinity`.

### Fix Focus Areas
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[338-350]

### Suggested fix
Compute `expectedNonIsolated` as `onlineCPUs.Difference(isolatedWithOvsDpdk)` (use `nodes.GetOnlineCPUsSet(...)`), then compare `systemd.cpu_affinity` to `expectedNonIsolated` (set equality). If you still want to assert reserved behavior, assert `expectedReserved` is a subset of the parsed affinity set, not equal.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. isolcpus misses OvsDpdk CPUs 🐞 Bug ≡ Correctness
Description
The new isolcpus expectation is built from profile.Spec.CPU.Isolated only, but tuned generates
isolcpus from (Isolated ∪ OvsDpdk). On profiles with OvsDpdk configured, this assertion can be wrong
and can intermittently fail due to string-substring matching rather than set comparison.
Code

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[R330-334]

+			expectedIsol := isolPrefix + expectedIsolated.String()
+			for _, node := range workerRTNodes {
+				cmdline, err := chkCmdLineFn(context.TODO(), &node)
+				Expect(err).ToNot(HaveOccurred())
+				Expect(cmdline).To(ContainSubstring(expectedIsol))
Relevance

●●● Strong

Correctness fix: align isolcpus expectation with tuned behavior and compare sets, not substrings.

PR-#1397

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The test derives expectedIsolated from CPU.Isolated only, but tuned unions OvsDpdk into the isolated
set and uses it to template the cmdline isolcpus parameter, so the expectation can diverge from real
behavior.

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[243-252]
pkg/performanceprofile/controller/performanceprofile/components/tuned/tuned.go[65-77]
assets/performanceprofile/tuned/openshift-node-performance[155-159]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`isolcpus` on the kernel cmdline is generated by tuned from the isolated CPU set **including** `spec.cpu.ovsDpdk`. The test currently derives `expectedIsolated` only from `spec.cpu.isolated` and then checks `ContainSubstring`, which can be incorrect for profiles with OVS-DPDK CPUs.

### Issue Context
In tuned rendering, OVS-DPDK CPUs are unioned into the isolated set before templating `isolated_cores`, and `cmdline_isolation` uses `${isolated_cores}`.

### Fix Focus Areas
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[239-252]
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[324-336]

### Suggested fix
1) When building `expectedIsolated`, union in `profile.Spec.CPU.OvsDpdk` when present (same semantics as tuned).
2) Prefer parsing the `isolcpus=...` value from `/proc/cmdline` and comparing CPU sets (order/format independent) instead of `ContainSubstring`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. ReservedSystemCPUs ignores shared CPUs 🐞 Bug ≡ Correctness
Description
The new ReservedSystemCPUs expectation unions OvsDpdk CPUs but does not include Shared CPUs when
Mixed CPUs is enabled, even though kubeletconfig generation does. This can cause false failures on
valid mixed-CPU profiles.
Code

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[R368-373]

+			expectedReservedCPUs := expectedReserved
+			if profile.Spec.CPU.OvsDpdk != nil && *profile.Spec.CPU.OvsDpdk != "" {
+				ovsDpdkCPUs, err := cpuset.Parse(string(*profile.Spec.CPU.OvsDpdk))
+				Expect(err).ToNot(HaveOccurred())
+				expectedReservedCPUs = expectedReservedCPUs.Union(ovsDpdkCPUs)
+			}
Relevance

●●● Strong

Correctness fix: tests should mirror kubeletconfig generation logic; team accepts reducing
hardcoded/partial expectations.

PR-#1302
PR-#1458

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Kubelet ReservedSystemCPUs is generated to include shared CPUs when Mixed CPUs is enabled, but the
new test expectation omits them, so it can diverge from generated kubelet configuration.

pkg/performanceprofile/controller/performanceprofile/components/kubeletconfig/kubeletconfig.go[160-182]
pkg/performanceprofile/controller/performanceprofile/components/profile/profile.go[95-103]
test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[367-385]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
When Mixed CPUs is enabled, the controller sets `ReservedSystemCPUs = reserved ∪ ovsDpdk ∪ shared`. The test currently sets expected ReservedSystemCPUs to `reserved ∪ ovsDpdk` only.

### Issue Context
Mixed CPUs enablement is determined from the profile (`spec.cpu.shared` plus `spec.workloadHints.mixedCpus`) and feature gates; kubeletconfig generation unions shared CPUs only when mixed CPUs is enabled.

### Fix Focus Areas
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[367-386]

### Suggested fix
Mirror controller logic:
- Always union OvsDpdk into expected.
- If `profile.Spec.CPU.Shared` is set and `profile.Spec.WorkloadHints.MixedCpus` is true (and any e2e-available feature-gate check indicates enabled), union Shared into expected before comparing to `kc.ReservedSystemCPUs`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. non_isolcpus only presence-checked ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The new tuned.non_isolcpus test only checks that the parameter exists in /proc/cmdline and does not
validate its value, so regressions in the mask computation or updates can slip through. This reduces
coverage compared to the prior value-matching check.
Code

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[R315-320]

+		It("[test_id:28025] verify that cpu affinity mask matches the performance profile", func() {
+			for _, node := range workerRTNodes {
+				cmdline, err := chkCmdLineFn(context.TODO(), &node)
+				Expect(err).ToNot(HaveOccurred())
+				re := regexp.MustCompile(`tuned.non_isolcpus=\S+`)
+				Expect(re.FindString(cmdline)).ToNot(BeEmpty(), "tuned.non_isolcpus parameter not found in %q", cmdline)
Relevance

●●● Strong

Team often strengthens e2e assertions to avoid false positives; value-check improves coverage.

PR-#1397
PR-#1302

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The current test asserts only presence, while tuned’s template indicates the parameter should encode
a specific non-isolated cpumask value; the repo includes utilities to compute such masks, enabling a
precise assertion.

test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[315-321]
assets/performanceprofile/tuned/openshift-node-performance[149-150]
pkg/performanceprofile/controller/performanceprofile/components/utils.go[37-84]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The test for `tuned.non_isolcpus` currently asserts only that the token exists, which doesn't validate the CPU mask is correct for the profile.

### Issue Context
`tuned.non_isolcpus` in the tuned bootloader template is derived from the non-isolated CPU set (invert of isolated). The codebase already contains helpers to compute hex mask lists from CPU lists.

### Fix Focus Areas
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[315-322]

### Suggested fix
1) Derive `expectedNonIsolated` from online CPUs minus isolated (including ovsdpdk).
2) Convert to an expected mask string using `components.CPUListToMaskList(expectedNonIsolated.String())`.
3) Extract the cmdline value for `tuned.non_isolcpus=` and compare (exact match or normalized match).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can group findings by type and pick your Finding display, from Minimal to Full

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +330 to +334
expectedIsol := isolPrefix + expectedIsolated.String()
for _, node := range workerRTNodes {
cmdline, err := chkCmdLineFn(context.TODO(), &node)
Expect(err).ToNot(HaveOccurred())
Expect(cmdline).To(ContainSubstring(expectedIsol))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Isolcpus misses ovsdpdk cpus 🐞 Bug ≡ Correctness

The new isolcpus expectation is built from profile.Spec.CPU.Isolated only, but tuned generates
isolcpus from (Isolated ∪ OvsDpdk). On profiles with OvsDpdk configured, this assertion can be wrong
and can intermittently fail due to string-substring matching rather than set comparison.
Agent Prompt
### Issue description
`isolcpus` on the kernel cmdline is generated by tuned from the isolated CPU set **including** `spec.cpu.ovsDpdk`. The test currently derives `expectedIsolated` only from `spec.cpu.isolated` and then checks `ContainSubstring`, which can be incorrect for profiles with OVS-DPDK CPUs.

### Issue Context
In tuned rendering, OVS-DPDK CPUs are unioned into the isolated set before templating `isolated_cores`, and `cmdline_isolation` uses `${isolated_cores}`.

### Fix Focus Areas
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[239-252]
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[324-336]

### Suggested fix
1) When building `expectedIsolated`, union in `profile.Spec.CPU.OvsDpdk` when present (same semantics as tuned).
2) Prefer parsing the `isolcpus=...` value from `/proc/cmdline` and comparing CPU sets (order/format independent) instead of `ContainSubstring`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

By default profiles will not have ovsdpdk configured.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

we have separate tests for ovsdpdk where profile will be configured with ovsdpdk when those tests run

Comment thread test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go Outdated
Comment thread test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go Outdated
Comment on lines +368 to +373
expectedReservedCPUs := expectedReserved
if profile.Spec.CPU.OvsDpdk != nil && *profile.Spec.CPU.OvsDpdk != "" {
ovsDpdkCPUs, err := cpuset.Parse(string(*profile.Spec.CPU.OvsDpdk))
Expect(err).ToNot(HaveOccurred())
expectedReservedCPUs = expectedReservedCPUs.Union(ovsDpdkCPUs)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

4. Reservedsystemcpus ignores shared cpus 🐞 Bug ≡ Correctness

The new ReservedSystemCPUs expectation unions OvsDpdk CPUs but does not include Shared CPUs when
Mixed CPUs is enabled, even though kubeletconfig generation does. This can cause false failures on
valid mixed-CPU profiles.
Agent Prompt
### Issue description
When Mixed CPUs is enabled, the controller sets `ReservedSystemCPUs = reserved ∪ ovsDpdk ∪ shared`. The test currently sets expected ReservedSystemCPUs to `reserved ∪ ovsDpdk` only.

### Issue Context
Mixed CPUs enablement is determined from the profile (`spec.cpu.shared` plus `spec.workloadHints.mixedCpus`) and feature gates; kubeletconfig generation unions shared CPUs only when mixed CPUs is enabled.

### Fix Focus Areas
- test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go[367-386]

### Suggested fix
Mirror controller logic:
- Always union OvsDpdk into expected.
- If `profile.Spec.CPU.Shared` is set and `profile.Spec.WorkloadHints.MixedCpus` is true (and any e2e-available feature-gate check indicates enabled), union Shared into expected before comparing to `kc.ReservedSystemCPUs`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

…tests

The restricted and single-numa-node fixtures assumed that configuring
20 x 2Mi hugepages without a NUMA Node would split evenly across both
NUMA nodes (10/10). That is not how cmdline hugepages=N works: the
kernel places pages system-wide, and Memory Manager can see an uneven
split (for example 24Mi on NUMA 0 and 16Mi on NUMA 1). With 24Mi free
on one node, a Guaranteed pod requesting 24Mi hugepages + 2 CPUs was
admitted instead of failing with TopologyAffinityError.

Pin 10 x 2Mi hugepages on each NUMA node so each zone has only 20Mi,
restoring the rejection expectation. Also DeferCleanup test pods so
flake retries do not leak hugepages from a failed attempt.

AI Attribution: AIA Human-AI blend, New content, Human-initiated, Reviewed, Cursor 3.0.16 v1.0

Signed-off-by: Niranjan M.R <mniranja@redhat.com>
Hardcoding isolated=1-2 and reserved=0,3 on large-CPU nodes inflated
tuned.non_isolcpus and systemd.cpu_affinity, which could drop later
cmdline args such as hugepages and break test_id:34081. Keep the
profile's CPU set and assert isolcpus, affinity, and ReservedSystemCPUs
against those values instead.

- Add FindCmdlineParam helper to nodes package for parsing /proc/cmdline
  parameters by splitting on whitespace instead of using regex
- Compare isolcpus using exact argument match instead of ContainSubstring
- Compare systemd.cpu_affinity against non-isolated CPUs (online \ isolated)
  instead of reserved, matching tuned's not_isolated_cores_expanded
- Validate tuned.non_isolcpus mask value against expected non-isolated
  CPU mask instead of only checking presence
- Simplify ReservedSystemCPUs to compare directly against reserved CPUs

Signed-off-by: Niranjan M.R <mniranja@redhat.com>
AI Attribution: AIA Human-AI blend, New content, Human-initiated, Reviewed, Cursor 3.0.16 v1.0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go (1)

151-158: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Check the WaitForCondition error before checking the event.

err := checkPodEvent(...) shadows the outer error returned by WaitForCondition. The same pattern occurs in the second test at lines 512–514. Assert the wait error immediately and use a separate variable for the event error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go`
around lines 151 - 158, The WaitForCondition result is shadowed before its error
is checked. In the test flow around WaitForCondition and checkPodEvent, assert
or handle the returned wait error immediately, then store the event-check result
in a distinct variable; apply the same change to the corresponding second-test
flow.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go`:
- Around line 101-113: The hugepage setup currently hardcodes NUMA IDs 0 and 1,
which may not match topology IDs from lscpu. Update the surrounding
memory-manager test flow to derive and reuse the IDs returned by GetNumaNodes
for hugepage Node values and affinity assertions, and skip topologies that do
not provide the required NUMA nodes.

---

Outside diff comments:
In `@test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go`:
- Around line 151-158: The WaitForCondition result is shadowed before its error
is checked. In the test flow around WaitForCondition and checkPodEvent, assert
or handle the returned wait error immediately, then store the event-check result
in a distinct variable; apply the same change to the corresponding second-test
flow.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 221f0e82-3ef4-492e-af0b-0a6625bdcaba

📥 Commits

Reviewing files that changed from the base of the PR and between 4a85eaf and ba99de2.

📒 Files selected for processing (4)
  • test/e2e/performanceprofile/functests/2_performance_update/memorymanager.go
  • test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go
  • test/e2e/performanceprofile/functests/utils/nodes/nodes.go
  • test/e2e/performanceprofile/functests/utils/nodes/nodes_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/e2e/performanceprofile/functests/2_performance_update/updating_profile.go

@mrniranjan
mrniranjan marked this pull request as ready for review August 11, 2026 12:59
@openshift-ci
openshift-ci Bot requested review from Tal-or and jmencak August 11, 2026 13:00
@mrniranjan mrniranjan changed the title WIP: E2E: Minor fixes to Memory Manager and hugepages split tests E2E: Minor fixes to Memory Manager and hugepages split tests Aug 11, 2026
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 11, 2026
@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Aug 21, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e-aws-operator
/test e2e-aws-ovn
/test e2e-aws-ovn-techpreview
/test e2e-gcp-pao
/test e2e-gcp-pao-updating-profile
/test e2e-gcp-pao-workloadhints
/test e2e-hypershift
/test e2e-hypershift-pao
/test e2e-no-cluster
/test e2e-upgrade

@openshift-ci

openshift-ci Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: MarSik, mrniranjan

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 21, 2026

@ffromani ffromani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

/lgtm

assuming we want to have Expect()ations in (Custom)BeforeAll

@Tal-or

Tal-or commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

/retest

@openshift-ci

openshift-ci Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

@mrniranjan: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-gcp-pao-updating-profile ba99de2 link true /test e2e-gcp-pao-updating-profile
ci/prow/e2e-aws-operator ba99de2 link true /test e2e-aws-operator

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants