Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache current process object to avoid performance hit #5597

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

haipz
Copy link

@haipz haipz commented Nov 2, 2024

GetCurrentProcessMemoryUsage will be called by src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Windows/WindowsContainerSnapshotProvider.cs from GetSnapshot method, which will be triggered every 1 second by default. And also this will be called by _ = meter.CreateObservableGauge(name: ResourceUtilizationInstruments.ProcessMemoryUtilization, observeValue: () => MemoryPercentage(() => _processInfo.GetCurrentProcessMemoryUsage())); with default interval: 5 seconds.

image

Microsoft Reviewers: Open in CodeFlow

Related issue: #5588

Refer to another similar fix in Otel: open-telemetry/opentelemetry-dotnet-contrib#2286

@haipz haipz closed this Nov 2, 2024
@haipz haipz reopened this Nov 2, 2024
@haipz haipz force-pushed the cachecurrentprocessinprocessinfo branch from c8ac8de to 995dc27 Compare November 2, 2024 08:43
@haipz haipz marked this pull request as ready for review November 2, 2024 08:46
@evgenyfedorov2
Copy link
Contributor

Did you test it and it worked as expected?

@haipz
Copy link
Author

haipz commented Nov 4, 2024

Did you test it and it worked as expected?

The value of Process.WorkingSet64 will not update unless Process.Refresh() is called. This method retrieves the latest process information, so it's necessary to call _currentProcess.Refresh() before accessing WorkingSet64.

@danespinosa
Copy link
Contributor

Did you test it and it worked as expected?

The value of Process.WorkingSet64 will not update unless Process.Refresh() is called. This method retrieves the latest process information, so it's necessary to call _currentProcess.Refresh() before accessing WorkingSet64.

We need to be wise about the refresh, refresh literally disposes all handles to the process and the first call to the Process object it gets the handle again and is able to get the new values, at that point getting a new process or refreshing the process is the same cost, so from that perspective we can't do much as far as I understand, as long as the extension respects the sampling rate, I think the best would be to have better defaults that are not so aggressive?

Refresh source code: https://source.dot.net/#System.Diagnostics.Process/System/Diagnostics/Process.cs,173ad2a094ae7507,references

@evgenyfedorov2
Copy link
Contributor

Did you test it and it worked as expected?

The value of Process.WorkingSet64 will not update unless Process.Refresh() is called. This method retrieves the latest process information, so it's necessary to call _currentProcess.Refresh() before accessing WorkingSet64.

We need to be wise about the refresh, refresh literally disposes all handles to the process and the first call to the Process object it gets the handle again and is able to get the new values, at that point getting a new process or refreshing the process is the same cost, so from that perspective we can't do much as far as I understand, as long as the extension respects the sampling rate, I think the best would be to have better defaults that are not so aggressive?

Refresh source code: https://source.dot.net/#System.Diagnostics.Process/System/Diagnostics/Process.cs,173ad2a094ae7507,references

That's why I am asking if it works without the Refresh() or not :) If it does, probably we can get away with it. If it does not (e.g. WorkingSet value is not getting updated), we can't do anything but use new Process/Refresh()

@haipz
Copy link
Author

haipz commented Nov 5, 2024

Did you test it and it worked as expected?

The value of Process.WorkingSet64 will not update unless Process.Refresh() is called. This method retrieves the latest process information, so it's necessary to call _currentProcess.Refresh() before accessing WorkingSet64.

We need to be wise about the refresh, refresh literally disposes all handles to the process and the first call to the Process object it gets the handle again and is able to get the new values, at that point getting a new process or refreshing the process is the same cost, so from that perspective we can't do much as far as I understand, as long as the extension respects the sampling rate, I think the best would be to have better defaults that are not so aggressive?
Refresh source code: https://source.dot.net/#System.Diagnostics.Process/System/Diagnostics/Process.cs,173ad2a094ae7507,references

That's why I am asking if it works without the Refresh() or not :) If it does, probably we can get away with it. If it does not (e.g. WorkingSet value is not getting updated), we can't do anything but use new Process/Refresh()

Refresh() vs. new Process() could potentially improve performance by 0.1%.

Since GetSnapshot calls for memory every second and MemoryPercentage calls for memory every five seconds, we could potentially improve performance by 16.67% if we cache the result of WorkingSet64 for at least one second.

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