Skip to content

Commit a012348

Browse files
committed
Read canonical Linux CPU and memory file boundaries in benchmark evidence
1 parent 6c99f16 commit a012348

8 files changed

Lines changed: 170 additions & 21 deletions

File tree

‎docs/Features/BenchmarkComparisons/ScalingQualification.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,33 @@ the production parser. A supported Linux envelope test must assert its actual
9999
value instead of conditionally omitting a null result. This source correction
100100
changes no sidecar schema, workload, bounds or qualification requirements.
101101

102+
TASK-SCALE-NATIVE-TEXT-026 repairs the existing REQ/AC-SCALE-016 CPU
103+
file-format boundary. Normalize only leading/trailing file whitespace before
104+
the existing two-space-separated-field grammar and positive quota/period
105+
validation; native newline-terminated `cpu.max` must retain its real limit.
106+
Keep unlimited/root handling, ancestor minima and bounded reads unchanged.
107+
The independent actual-Linux oracle performs its own boundary normalization,
108+
without calling the production parser. Focused native-format parser controls
109+
cover newline/outer whitespace, unlimited/root and minima, malformed interior
110+
fields and healthy follow-up after rejection. They do not manufacture cgroup
111+
proof: the existing actual Linux hardware/envelope test must still pass from
112+
original exact-source GitHub Actions normal/scalar execution. The interrupted
113+
e0678227 run 37927497154 supplies the original diagnostic "Native cgroup CPU
114+
limit was malformed"; its partial cases are not complete qualification.
115+
116+
The same stage normalizes leading/trailing native `memory.current` file
117+
whitespace at ScaleServerProcessMetrics before the sampler consumes its actual
118+
counter. Preserve nonnegative Int64 bytes, including zero, without scaling,
119+
clamping or invented values. Reject signs, overflow, interior whitespace and
120+
malformed numbers; retain existing sample invalidation, original cgroup/PID
121+
identity, byte bounds, cadence and schema. Normative native-format controls
122+
assert newline/outer whitespace, zero, Int64 maximum, malformed rejection and
123+
healthy follow-up. Linux's [cgroup read_u64 output](https://github.com/torvalds/linux/blob/master/kernel/cgroup/cgroup.c)
124+
emits a newline for the [memory current counter](https://github.com/torvalds/linux/blob/master/mm/memcontrol.c);
125+
the [CPU quota/period output](https://github.com/torvalds/linux/blob/master/kernel/sched/core.c)
126+
also ends with a newline. These parser controls supplement the real Linux
127+
envelope and complete genuine server-resource evidence gates.
128+
102129
### Native probe cancellation regression repair
103130

104131
TASK-SCALE-NATIVE-PIPE-025 extends the existing REQ/AC-SCALE-016 settlement

‎docs/implementation/status.json‎

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,18 @@
2525
"websiteBaselineInputs": 1716,
2626
"runtimeQualified": false,
2727
"fullTaskComplete": false,
28-
"sourceStage": "Shared native runner/adapters and exclusive RF3 load implemented. Original e0678227 full solution build, formatter and repository rules passed. All 22 native document cases then failed strict fixture profile selection before acquisition: Benchmarks:Profile was supplied instead of canonical Benchmarks:EvidenceProfile. The fixture now uses existing ComparisonWorkerSelection keys. Native resource pipe deadlock repair with two real PID-bound overflow/healthy follow-up cases is delivered in 50d2a505; original exact-source normal/scalar verification remains pending. Cgroup envelope diagnosis, actual native workloads, heavy RF3 and complete scale qualification remain open; all verification is GitHub Actions only.",
28+
"sourceStage": "Shared native workloads and exclusive RF3 load are implemented. Original e0678227 full solution build passed with zero warnings/errors; formatter and repository rules passed. Its interrupted contracts printed 771 passed cases and one CPU-envelope failure without terminal qualification, and old yes was killed by job cleanup. CPU and memory file boundaries now normalize kernel line endings while retaining strict quota/counter grammar, root/minimum/identity contracts and bounds; 23 normative positive/negative/healthy format cases supplement required actual Linux evidence. Native pipe settlement is delivered in 50d2a505 and canonical fixture evidence-profile keys in 6c99f16a. Exact-source normal/scalar, actual native document operations, exclusive 1M RF3 and complete scale remain unqualified. All verification is GitHub Actions only.",
2929
"verification": {
30-
"canonicalBuild": "original_linux_e0678227_full_solution_build_step_passed; completed_original_log_counts_pending; latest_profile_key_and_native_pipe_source_pending",
31-
"format": "original_linux_e0678227_canonical_formatter_step_passed; latest_profile_key_and_native_pipe_source_pending",
32-
"governance": "original_linux_e0678227_repository_rules_step_passed; latest_profile_key_and_native_pipe_source_pending",
30+
"canonicalBuild": "original_linux_e0678227_full_solution_passed_0_warnings_0_errors; latest_native_kernel_text_source_pending",
31+
"format": "original_linux_e0678227_canonical_formatter_passed; latest_native_kernel_text_source_pending",
32+
"governance": "original_linux_e0678227_repository_rules_passed; latest_native_kernel_text_source_pending",
3333
"nativeRegressions": "original_linux_0c0378e6_resource_models_107_passed_and_request_admission_3_passed_and_document_admission_15_passed_all_zero_failed_skipped; actual_native_step_22_total_22_failed_0_passed_0_skipped_at_fixture_startup_before_operations; isolated_AppHost_fixture_source_repair_authored; original_852_contracts_interrupted_without_terminal_summary_or_qualification_752_passed_case_lines_and_19_failed_case_lines_observed; controlled_repairs_authored; native_cgroup_envelope_cause_open; heavy_gates_skipped; earlier_local_failure_history_retained",
3434
"actualLinuxScale": "pending_original_exact_source_workflow",
3535
"workflowSyntax": "original_linux_0c0378e6_workflow_started_and_plan_passed; latest_repair_source_pending",
3636
"canonicalPlanner": "original_linux_0c0378e6_plan_passed_418_documents_and_1898_total_named_database_cells",
3737
"websiteSourceClosure": "original_linux_0388aec6_website_37924688317_qualification_job_113800692024_passed_source_gate_and_406_tests_0_failed_0_skipped; publish_job_113805231381_correctly_rejected_changed_main_SHA_before_deployment",
38-
"nativeProbeSettlement": "original_linux_852aef07_contract_suite_interrupted_without_terminal_bounds_case_and_cleanup_killed_yes_pid9158; six_reviewed_individual_pipe_PID_oracle_source_paths_delivered_in_50d2a505; exact_source_normal_scalar_GitHub_qualification_pending"
38+
"nativeProbeSettlement": "original_linux_852aef07_contract_suite_interrupted_without_terminal_bounds_case_and_cleanup_killed_yes_pid9158; six_reviewed_individual_pipe_PID_oracle_source_paths_delivered_in_50d2a505; exact_source_normal_scalar_GitHub_qualification_pending",
39+
"nativeKernelText": "original_linux_e0678227_CPU_envelope_failure_visible; CPU_period_and_memory_current_newline_formats_verified_from_primary_Linux_source; boundary_only_repairs_and_11_CPU_plus_12_memory_normative_cases_authored; genuine_Linux_envelope_and_server_resource_qualification_pending"
3940
},
4041
"latestOriginalLinux": {
4142
"sourceCommit": "852aef0796e8455e155e1769af9e137d861b2a56",
@@ -81,19 +82,24 @@
8182
"scaleExecuted": false
8283
},
8384
"newestOriginalBuild": {
84-
"sourceCommit": "0388aec6868b31239db2e918898b8d121d60d393",
85-
"runId": 37924688342,
86-
"jobId": 113802654137,
87-
"receipt": "https://github.com/managedcode/KeyLoad/actions/runs/37924688342/job/113802654137",
88-
"conclusion": "failure",
85+
"sourceCommit": "e0678227e4f51d15a1c9c924ea06cfab14ab19ed",
86+
"runId": 37927497154,
87+
"jobId": 113810281715,
88+
"receipt": "https://github.com/managedcode/KeyLoad/actions/runs/37927497154/job/113810281715",
89+
"conclusion": "cancelled_after_failed_image_gate_and_known_native_probe_deadlock_to_release_corrected_workflow_queue",
8990
"buildPassed": true,
9091
"buildWarnings": 0,
9192
"buildErrors": 0,
92-
"formatterPassed": false,
93-
"formatterDiagnosticCount": 23,
94-
"formatterFailure": "HeavyDocumentLoadAdmissionTests switch-arm newlines; exact manual source repair authored",
95-
"contractsExecuted": false,
96-
"scalarContractsExecuted": false
93+
"formatterPassed": true,
94+
"repositoryRulesPassed": true,
95+
"contractSuiteCompleted": false,
96+
"contractPassedCaseLinesObserved": 771,
97+
"contractFailedCaseLinesObserved": 1,
98+
"contractFailure": "Supported Linux host evidence was unavailable.; Native cgroup CPU limit was malformed.",
99+
"orphanNativeProcessKilledByJobCleanup": "yes pid9867",
100+
"scalarContractsExecuted": false,
101+
"artifactId": 11615382803,
102+
"artifactDigest": "sha256:8af74567443e190c829f4b05203a9612b9ec8205460a4a65cdb045800ecf98b0"
97103
},
98104
"qualification": "No fabricated measurements, no performance winner, no full coverage or production claim; authentic complete current-source Linux workloads and required recovery/RF3 gates remain open.",
99105
"newestOriginalImageBuild": {

‎src/KeyLoad.AppHost/Features/BenchmarkComparisons/Hardware/ScaleServerCgroupEnvelopeReader.cs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ internal static class ScaleServerCgroupEnvelopeReader
8383
? null : (cpuText, memoryText, setText);
8484
}
8585

86-
private static bool TryAccumulateCpuLimit(string cpuText, bool isRoot, ref decimal? cpu)
86+
internal static bool TryAccumulateCpuLimit(string cpuText, bool isRoot, ref decimal? cpu)
8787
{
88-
var parts = cpuText.Split(WhitespaceSeparator, StringSplitOptions.RemoveEmptyEntries);
88+
var parts = cpuText.Trim().Split(WhitespaceSeparator, StringSplitOptions.RemoveEmptyEntries);
8989
if (isRoot && parts.Length == PeriodFieldIndex && parts[NoLimit] == Unlimited)
9090
{
9191
return true;

‎src/KeyLoad.AppHost/Features/BenchmarkComparisons/Observations/ScaleServerProcessMetrics.cs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ internal static bool TryUsage(string stats, out long usage)
9191
return long.TryParse(row?[UsagePrefix.Length..], NumberStyles.None, CultureInfo.InvariantCulture, out usage);
9292
}
9393

94+
internal static bool TryMemoryCurrent(string text, out long bytes)
95+
{
96+
const long MinimumMemoryBytes = 0;
97+
return long.TryParse(text.Trim(), NumberStyles.None, CultureInfo.InvariantCulture, out bytes)
98+
&& bytes >= MinimumMemoryBytes;
99+
}
100+
94101
}
95102

96103
internal static class ProcessIdentity

‎src/KeyLoad.AppHost/Features/BenchmarkComparisons/Observations/ScaleServerResourceSampler.cs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using System.Globalization;
2-
31
namespace KeyLoad.AppHost.Features.BenchmarkComparisons;
42

53
internal sealed class ScaleServerResourceSampler(string resourceName, string[] expectedMountTargets)
@@ -155,7 +153,7 @@ private async Task<bool> CommitSampleAsync(string directory, string mountDescrip
155153
}
156154

157155
if (!ScaleServerProcessMetrics.TryUsage(cpuStats, out var usage)
158-
|| !long.TryParse(memoryCurrent, NumberStyles.None, CultureInfo.InvariantCulture, out var currentMemory)
156+
|| !ScaleServerProcessMetrics.TryMemoryCurrent(memoryCurrent, out var currentMemory)
159157
|| _samples > BoundaryValue && usage < _lastCpuUsec)
160158
{
161159
return InvalidateAfterStart();
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using KeyLoad.AppHost.Features.BenchmarkComparisons;
2+
3+
namespace KeyLoad.UnitTests.Features.BenchmarkComparisons;
4+
5+
internal sealed class ScaleServerCgroupCpuFormatTests
6+
{
7+
private const string NativeLimited = "100000 100000\n";
8+
private const string OuterWhitespaceLimited = " \t100000 100000\r\n ";
9+
private const string NativeUnlimited = "max 100000\n";
10+
private const string RootUnlimited = " \tmax\n";
11+
private const string LargerLimit = "200000 100000\n";
12+
private const string ZeroQuota = "0 100000\n";
13+
private const string ZeroPeriod = "100000 0\n";
14+
private const string MissingPeriod = "100000\n";
15+
private const string ExtraField = "100000 100000 100000\n";
16+
private const string SignedQuota = "+100000 100000\n";
17+
private const string OverflowPeriod = "100000 9223372036854775808\n";
18+
private const string InteriorNewline = "100000 \n100000\n";
19+
private const string InteriorTab = "100000\t100000\n";
20+
private const decimal OneCore = 1;
21+
22+
[Test]
23+
[Arguments(NativeLimited)]
24+
[Arguments(OuterWhitespaceLimited)]
25+
public async Task AcScale016NativeCpuFileWhitespacePreservesPositiveLimitAndAncestorMinimum(string text)
26+
{
27+
decimal? cpu = null;
28+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(text, isRoot: false, ref cpu)).IsTrue();
29+
await Assert.That(cpu).IsEqualTo(OneCore);
30+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(LargerLimit, isRoot: false, ref cpu)).IsTrue();
31+
await Assert.That(cpu).IsEqualTo(OneCore);
32+
}
33+
34+
[Test]
35+
public async Task AcScale016NativeUnlimitedAndRootWhitespacePreserveFiniteAncestor()
36+
{
37+
decimal? cpu = null;
38+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(NativeUnlimited, isRoot: false, ref cpu)).IsTrue();
39+
await Assert.That(cpu).IsNull();
40+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(NativeLimited, isRoot: false, ref cpu)).IsTrue();
41+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(RootUnlimited, isRoot: true, ref cpu)).IsTrue();
42+
await Assert.That(cpu).IsEqualTo(OneCore);
43+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(RootUnlimited, isRoot: false, ref cpu)).IsFalse();
44+
await Assert.That(cpu).IsEqualTo(OneCore);
45+
}
46+
47+
[Test]
48+
[Arguments(ZeroQuota)]
49+
[Arguments(ZeroPeriod)]
50+
[Arguments(MissingPeriod)]
51+
[Arguments(ExtraField)]
52+
[Arguments(SignedQuota)]
53+
[Arguments(OverflowPeriod)]
54+
[Arguments(InteriorNewline)]
55+
[Arguments(InteriorTab)]
56+
public async Task AcScale016MalformedCpuFieldsRejectWithoutMutatingLimitThenHealthyFollowUp(string text)
57+
{
58+
decimal? cpu = OneCore;
59+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(text, isRoot: false, ref cpu)).IsFalse();
60+
await Assert.That(cpu).IsEqualTo(OneCore);
61+
await Assert.That(ScaleServerCgroupEnvelopeReader.TryAccumulateCpuLimit(NativeLimited, isRoot: false, ref cpu)).IsTrue();
62+
await Assert.That(cpu).IsEqualTo(OneCore);
63+
}
64+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using KeyLoad.AppHost.Features.BenchmarkComparisons;
2+
3+
namespace KeyLoad.UnitTests.Features.BenchmarkComparisons;
4+
5+
internal sealed class ScaleServerMemoryCurrentFormatTests
6+
{
7+
private const string NativeCounter = "123456\n";
8+
private const string OuterWhitespaceCounter = " \t123456\r\n ";
9+
private const string NativeZero = "0\n";
10+
private const string NativeMaximum = "9223372036854775807\n";
11+
private const string SignedPositive = "+123456\n";
12+
private const string Negative = "-1\n";
13+
private const string Overflow = "9223372036854775808\n";
14+
private const string Fractional = "123456.0\n";
15+
private const string InteriorSpace = "123 456\n";
16+
private const string ExtraLine = "123456\n0\n";
17+
private const string Unlimited = "max\n";
18+
private const long CounterBytes = 123456;
19+
private const long ZeroBytes = 0;
20+
21+
[Test]
22+
[Arguments(NativeCounter, CounterBytes)]
23+
[Arguments(OuterWhitespaceCounter, CounterBytes)]
24+
[Arguments(NativeZero, ZeroBytes)]
25+
[Arguments(NativeMaximum, long.MaxValue)]
26+
public async Task AcScale016NativeMemoryCounterFileWhitespacePreservesExactBytes(string text, long expected)
27+
{
28+
await Assert.That(ScaleServerProcessMetrics.TryMemoryCurrent(text, out var bytes)).IsTrue();
29+
await Assert.That(bytes).IsEqualTo(expected);
30+
}
31+
32+
[Test]
33+
[Arguments(SignedPositive)]
34+
[Arguments(Negative)]
35+
[Arguments(Overflow)]
36+
[Arguments(Fractional)]
37+
[Arguments(InteriorSpace)]
38+
[Arguments(ExtraLine)]
39+
[Arguments(Unlimited)]
40+
[Arguments(string.Empty)]
41+
public async Task AcScale016MalformedMemoryCounterRejectsThenHealthyFollowUp(string text)
42+
{
43+
await Assert.That(ScaleServerProcessMetrics.TryMemoryCurrent(text, out _)).IsFalse();
44+
await Assert.That(ScaleServerProcessMetrics.TryMemoryCurrent(NativeCounter, out var bytes)).IsTrue();
45+
await Assert.That(bytes).IsEqualTo(CounterBytes);
46+
}
47+
}

‎tests/KeyLoad.ComparisonTests/Features/BenchmarkComparisons/UnitContracts/Helpers/ScaleServerCgroupOracle.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private static decimal ReadCpuLimit(string directory, bool isRoot)
6666
{
6767
var path = Path.Combine(directory, CpuFile);
6868
var text = isRoot ? ReadRootLimit(path) : ReadBounded(path);
69-
var fields = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
69+
var fields = text.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
7070
if (isRoot && fields.Length == 1 && fields[0] == Unlimited)
7171
{
7272
return decimal.MaxValue;

0 commit comments

Comments
 (0)