Skip to content

PerformanceCounterCategory.ReadCategory() is taking larger memory allocation #101485

Open
@vsfeedback

Description

@vsfeedback

This issue has been moved from a ticket on Developer Community.


Our .NET Core app uses PerformanceCounterCategory.ReadCategory() method to read performance data for every around 15 seconds.
Currently we are trying to read performance data for around 10 categories.

The memory usage is high with the ReadCategory() method. Also, Gen 0 to Gen 1 promotion and Gen1 to Gen 2 promotion is higher because of this.

Here is the code:
public void ReadCounterValues()
{
InstanceDataCollectionCollection collection = this.pcCategory.ReadCategory();
ICollection values = collection. Values;

foreach (InstanceDataCollection value in values)
{
string categoryType = value. CounterName;
string counter = this. Category + "\" + categoryType;
int counterPositioninMap = this. CategoryTypes.FindIndex(x => string. Equals(x, categoryType, StringComparison.OrdinalIgnoreCase));

// skip reading performance data for the counters not listed in Environment.ini
if (counterPositioninMap < 0)
{
continue;
}

foreach (InstanceData data in value. Values)
{
string process = data. InstanceName;

// Check if the performance data need to be collected for overall resource usage only
if (this. Config.CollectOnlyOverallResourceUsage(counter))
{
if (!( string. Equals(process, Constants.SingleInstance) || string. Equals(process, Constants.Total)))
{
continue;
}

process = Constants.Total;
}
else if (string. Equals(process, Constants.Total) || string. Equals(process, Constants.IdleProcess))
{
// Skip reading counter values for Idle and total process instance
continue;
}

if (!this. ProcessToCounterValuesMap.TryGetValue(process, out var counterValues))
{
counterValues = Enumerable.Repeat(0f, this. TotalCountersInCategory). ToArray();
this. ProcessToCounterValuesMap.Add(process, counterValues);
}

if (!this. ProcessToCounterSamplesMap.TryGetValue(process, out var counterSamples))
{
counterSamples = Enumerable.Repeat(CounterSample.Empty, this. TotalCountersInCategory). ToArray();
this. ProcessToCounterSamplesMap.Add(process, counterSamples);
}

float counterValue = 0.0f;

// This value is calculated over the base line of
// (No of Logical CPUS * 100), So this is going to be a
// calculated over a baseline of more than 100.
if (string. Equals(counter, Constants.ProcessorTimePerfMonitorCounter, StringComparison.OrdinalIgnoreCase))
{
counterValue = counterValue / this.numberOfLogicalPrcessors;
}

counterValues[counterPositioninMap] += counterValue;
counterSamples[counterPositioninMap] = data. Sample;
this. ProcessToCounterValuesMap[process] = counterValues;
this. ProcessToCounterSamplesMap[process] = counterSamples;
}
}
}

ReadCounterValues() method is called from another main class through the below method:
private void CollectAndEmitCounterValues(string category)
{
// perfCounterCategory instance to read performance data related to a specific category.
PerfCounterCategory perfCounterCategory = new PerfCounterCategory(category, this.settings);

// Collect counter values set as samples count.
int sampleCount = 0;

// Use the stopwatch to emit the counter metrics for every 1 minnute.
Stopwatch sw = new Stopwatch();
sw. Start();

while (this.settings.EnableMachineMonitor)
{
// Read performance data from the machine for the category
perfCounterCategory.ReadCounterValues();

sampleCount++;

// Emit metrics for each counterType(say 'processor Time' under process category) under the category for every Constants.TimeToEmitCounterMetricInMillSec
if (sw. ElapsedMilliseconds >= Constants.TimeToEmitCounterMetricInMillSec)
{
// Get the average of the counter values for each performance counter based on number of samples collected.
perfCounterCategory.CalculateAverageOfCounterValues(sampleCount);

// Loop to emit metrics for each counter under a specific category.
foreach (string counter in perfCounterCategory.Counters)
{
int topMetricCount = this.settings.CountersList[counter]. EmitTopNMetrics;
long metricMinVal = this.settings.CountersList[counter]. MinMetricValue;
this. SortAndEmit(perfCounterCategory.GetValuesPerCounter(counter), counter, topMetricCount, metricMinVal);
}

// Clear the performance data values being collected to start new sample collection.
perfCounterCategory.ClearCounterValues();
sw. Restart();
sampleCount = 0;
}

// Counters shouldn't be used immediately.
Thread.Sleep(this.settings.SleepTimeForNextCounterValue);
}
}

Here is the profiler info related to this:
image.png

Can you please suggest the optimization here to reduce memory usage by ReadCategory() method?


Original Comments

Feedback Bot on 3/11/2024, 06:08 AM:

(private comment, text removed)


Original Solutions

(no solutions)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions