Skip to content

Fix container.cpu.time on Linux: report it as a counter in seconds - #7840

Open
evgenyfedorov2 wants to merge 3 commits into
dotnet:mainfrom
evgenyfedorov2:evgenyfedorov2-fix-linux-container-cpu-time
Open

evgenyfedorov2 wants to merge 3 commits into
dotnet:mainfrom
evgenyfedorov2:evgenyfedorov2-fix-linux-container-cpu-time

Conversation

@evgenyfedorov2

@evgenyfedorov2 evgenyfedorov2 commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Changes to container.cpu.time in LinuxUtilizationProvider:

  1. ObservableCounter with unit s instead of ObservableGauge with unit 1. Cumulative CPU time only increases, so it's a counter in seconds. That's how OpenTelemetry defines container.cpu.time and how Windows registers it (same unit and description).
  2. cpu.mode=user is CPU time in seconds instead of CPU cores in use. The value came from CpuUtilizationV2(), which returns the number of CPU cores in use: a rate, not a time. Now it's usage_usec from the process's cgroup cpu.stat (the container's cumulative CPU time), converted to seconds.
Microsoft Reviewers: Open in CodeFlow

With UseLinuxCalculationV2, container.cpu.time was an ObservableGauge with
unit "1" that reported the host's total /proc/stat time as system time and
the number of cores currently in use as user time. Computing the latter also
consumed the state shared with the container.cpu.limit.utilization and
container.cpu.request.utilization gauges.

It is now an ObservableCounter in seconds, as on Windows, reporting the
container's cumulative user and system CPU time from the cgroup v2 cpu.stat
file (user_usec and system_usec), falling back to the host's /proc/stat
values when cpu.stat doesn't exist.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@evgenyfedorov2
evgenyfedorov2 requested a review from a team as a code owner October 14, 2026 10:17
Copilot AI balanced review requested due to automatic review settings October 14, 2026 10:17

Copilot AI 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.

🟡 Changes recommended

Cumulative CPU-time conversion can overflow signed nanoseconds and produce non-monotonic counter values.

1 open finding
What changed in this PR

Aligns Linux cgroup v2 container.cpu.time with the documented cross-platform metric contract.

Changes:

  • Reports cumulative user/system CPU seconds from cpu.stat.
  • Uses an ObservableCounter<double> with unit s.
  • Adds parser, provider, isolation, and acceptance coverage.
File Description
src/​.../​ILinuxUtilizationParser.cs Adds the user/system CPU-time parser contract.
src/​.../​LinuxUtilizationParserCgroupV2.cs Parses cgroup and host CPU times.
src/​.../​LinuxUtilizationParserCgroupV1.cs Marks the v2 operation unsupported.
src/​.../​LinuxUtilizationProvider.cs Emits cumulative CPU seconds as a counter.
test/​.../​DummyLinuxUtilizationParser.cs Implements the new test contract.
test/​.../​LinuxUtilizationParserCgroupV2Tests.cs Covers parsing, fallback, and malformed input.
test/​.../​LinuxUtilizationParserCgroupV1Tests.cs Verifies unsupported behavior.
test/​.../​LinuxUtilizationProviderTests.cs Verifies metadata, values, and callback isolation.
test/​.../​AcceptanceTest.cs Updates end-to-end cgroup v2 expectations.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +655 to +657
// In cgroup v2, the Units are microseconds for user_usec and system_usec.
// We multiply by 1000 to convert to nanoseconds.
return (userMicroseconds * Thousand, systemMicroseconds * Thousand);
@evgenyfedorov2
evgenyfedorov2 marked this pull request as draft October 14, 2026 10:30
With UseLinuxCalculationV2, container.cpu.time was an ObservableGauge
with unit "1", and cpu.mode=user reported the number of cores in use
(CpuUtilizationV2), which also changed the state used by the
container.cpu.limit/request.utilization gauges.

Restore the design from dotnet#5806: an ObservableCounter with unit "s",
where cpu.mode=user is the container's cumulative CPU time from the
cgroup cpu.stat. cpu.mode=system is unchanged.

This replaces the user_usec/system_usec approach of the previous commit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@evgenyfedorov2 evgenyfedorov2 changed the title Fix container.cpu.time on Linux to report container CPU time in seconds Fix container.cpu.time on Linux: report it as a counter in seconds Oct 14, 2026
@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 92.71 🔻
Microsoft.Extensions.AI.OpenAI Line 75 68.24 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 57.54 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 92.76 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 68.57 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Extensions.Http.Diagnostics 94 95
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 86
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 89
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1634858&view=codecoverage-tab

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@evgenyfedorov2
evgenyfedorov2 marked this pull request as ready for review October 14, 2026 11:53
@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 92.71 🔻
Microsoft.Extensions.AI.OpenAI Line 75 68.24 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 57.54 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 92.76 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.21 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Extensions.Http.Diagnostics 94 95
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 86
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 85
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1635002&view=codecoverage-tab

unit: "1");

_ = meter.CreateObservableGauge(
_ = meter.CreateObservableCounter(

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.

It depends on backend but its a breaking a change, are we good as its supposed to be released in .net 11?

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.

do you remember or understand how we could have missed that? I personally don't remember and the incorrect instrument type looks like a really silly mistake. I couldn't find any previous discussions about instrument types here either.

I don't have a strong preference as to when to merge and release it. Can very well wait and release with 11.1, for instance.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants