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

Resource monitor #48501

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

t-davidbrown-msft
Copy link

  • add cpu monitor returns a float between 0 and 1
  • add memory monitor currently return a double between 0 and 1 (this is the current amount of memory a process is using divided by the total amount of memory on the host)
  • add tests for cpu monitor and memory monitor. Tests check for 0, less than 1, and null

- create method for monitoring CPU usage that works for all frameworks using System.Diagnostics.Process
- create one test for ensuring that the monitor works
Merging the latest changes into my feature branch
- add CpuMonitor interface
- add CpuMonitor tests
- change CurrentProcessorTime to be the current time on the processor minute the previous
- removed unnecessary refactor
- add SimulateCpuLoad to test suite to simulate loading the CPU
- add CoreCount Property to replace function calls to Environment.ProcessorCount
- readd default constructor
- add tests for monitoring interval that is below 100 milliseconds
- create processor directive to create memory monitor for netstandard2.0 or greater, but this is not a great implementation
- create method for MonitorMemoryUsage is otherwise good
- create tests to check whether it is below 1, above 0, and not null
- add cpu monitor returns a float between 0 and 1
- add memory monitor currently return a double between 0 and 1 (this is the current amount of memory a process is using divided by the total amount of memory on the host)
- add tests for cpu monitor and memory monitor. Tests check for 0, less than 1, and null
@github-actions github-actions bot added the Storage Storage Service (Queues, Blobs, Files) label Mar 1, 2025
@t-davidbrown-msft
Copy link
Author

t-davidbrown-msft commented Mar 1, 2025 via email

@azure-sdk
Copy link
Collaborator

azure-sdk commented Mar 1, 2025

API change check

API changes are not detected in this pull request.

/// <summary>
/// Interface for monitoring CPU usage.
/// </summary>
public interface IResourceMonitor
Copy link
Member

Choose a reason for hiding this comment

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

Any particular reason you needed an interface? While a good .NET practice, we don't typically use them in our SDKs because changing them can result in breaking changes. In this case, this thing will be internal so breaking changes won't be too big of a deal, but we still typically just stay away from them.


/// <summary>
/// Initalizes the CPU monitor.
///
/// This should be called early on in the job transfers.
/// </summary>
public CpuMonitor()
///
public ResourceMonitor() { }
Copy link
Member

Choose a reason for hiding this comment

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

We should either remove the default constructor or set a default monitoring interval. Right now, as-is the default constructor will result in an instance with a null monitoring interval which we probably want to avoid.

//});

Task.Run(() => MonitorCpuUsage(_cancellationTokenSource.Token));
Task.Run(() => MonitorMemoryUsage(_cancellationTokenSource.Token));
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, I think it would be better to have both running in the same thread since there is no reason to start and manage a thread for each. In fact, maybe one function that monitors both at the same time would make sense?

public void StopMonitoring()
{
if (!IsRunning)
throw new InvalidOperationException();
Copy link
Member

Choose a reason for hiding this comment

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

nit: Maybe we don't need to throw here? If it is already stopped, we are at the state we wanted so we could just return.

await Task.Delay(_monitoringInterval, cancellationToken).ConfigureAwait(false);
// This is the memory that is shown in the task manager
//long currentMemoryUsage = CurrentProcess.WorkingSet64;
long currentMemoryUsage = CurrentProcess.PrivateMemorySize64;
Copy link
Member

Choose a reason for hiding this comment

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

Hmm not sure which is better here, working set or private. I never really understood the difference...

// Use PInvoke here

#endif
MemoryUsage = (double)currentMemoryUsage / (double)totalPhysicalMemory;
Copy link
Member

Choose a reason for hiding this comment

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

So, I think we should start by keeping this simple and just saving current memory usage of our process. The way to get total memory usage here uses P/Invoke and seems Windows specific. We want to avoid P/Invoke at all costs, so we'd need to rethink this a bit. For now, I vote we just remove all this total memory and P/Invoke stuff.

//for (var i = 0; i < 1000; i++)
//{
// Assert.That(cpuMonitor.CpuUsage, Is.LessThan(1));
//}
Copy link
Member

Choose a reason for hiding this comment

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

Remove commented stuff or bring it back if needed.

public bool IsRunning { get; private set; }
private double PreviousProcessorTime { get; set; } = 0;
private double CurrentProcessorTime { get; set; }
private int CoreCount { get; } = Environment.ProcessorCount;
Copy link
Member

Choose a reason for hiding this comment

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

All private members should start with an _ and be camel case. So _previousProcessorTime, _currentProcessorTime , and _coreCount here.

We should also group all public members together followed by all private members.

Comment on lines +172 to +175
if (IsRunning)
return;

IsRunning = true;
Copy link
Member

Choose a reason for hiding this comment

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

Should this be behind a lock / semaphoreslim ?

Copy link
Member

Choose a reason for hiding this comment

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

Setting a boolean is atomic: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#96-atomicity-of-variable-references

Also I'm not sure we'll be using this from multiple threads since there will only be one per transfer manager and I think the transfer manager will be the one starting/stopping it.

// Process.TotalProcessorTime.TotlMilliseconds returns the processing time across all processors
// Environment.ProcessorCount returns then total number of cores (which includes physical cores plus hyper
// threaded cores
return (float)(CurrentProcessorTime - PreviousProcessorTime) / (float)(_monitoringInterval.TotalMilliseconds * CoreCount);
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this is necessary but should we look out for accidentally dividing by 0?

Copy link
Author

Choose a reason for hiding this comment

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

I just set a default _monitoringInterval to 1 second. But I think you're right; let me add something to ensure that we can't do like Chuck Norris 😏: Divide by 0. 🤣

Pulled main branch from the original repo. Merging updates into my
feature branch
This reverts commit f783722, reversing
changes made to b693812.
- remove interface
- change private properties to fields
- group private fields and properties together
- remove empty constructor and replace with constructor with default monitorInterval
- combine cpu and memory into one task; run on one thread
- get CPU and memory; then sleep
- return Bytes for memory usage
- remove totalMemory
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Storage Storage Service (Queues, Blobs, Files)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants