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

[Instrumentation.Process] Implement threadSafe Refresh() #664

Merged
merged 13 commits into from
Oct 10, 2022
96 changes: 79 additions & 17 deletions src/OpenTelemetry.Instrumentation.Process/ProcessMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
// limitations under the License.
// </copyright>

using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Reflection;
using System.Threading;
using Diagnostics = System.Diagnostics;

namespace OpenTelemetry.Instrumentation.Process;
Expand All @@ -24,38 +27,97 @@ internal class ProcessMetrics
{
internal static readonly AssemblyName AssemblyName = typeof(ProcessMetrics).Assembly.GetName();
internal static readonly Meter MeterInstance = new(AssemblyName.Name, AssemblyName.Version.ToString());
private static readonly Diagnostics.Process CurrentProcess = Diagnostics.Process.GetCurrentProcess();

static ProcessMetrics()
public ProcessMetrics(ProcessInstrumentationOptions options)
{
ThreadSafeInstrumentValues threadSafeInstrumentValues = new();

// TODO: change to ObservableUpDownCounter
MeterInstance.CreateObservableGauge(
"process.memory.usage",
() =>
{
CurrentProcess.Refresh();
return CurrentProcess.WorkingSet64;
},
() => threadSafeInstrumentValues.GetMemoryUsage(),
unit: "By",
description: "The amount of physical memory in use.");

// TODO: change to ObservableUpDownCounter
MeterInstance.CreateObservableGauge(
"process.memory.virtual",
() =>
{
CurrentProcess.Refresh();
return CurrentProcess.VirtualMemorySize64;
},
() => threadSafeInstrumentValues.GetVirtualMemoryUsage(),
unit: "By",
description: "The amount of committed virtual memory.");
}

/// <summary>
/// Initializes a new instance of the <see cref="ProcessMetrics"/> class.
/// </summary>
/// <param name="options">The options to define the metrics.</param>
public ProcessMetrics(ProcessInstrumentationOptions options)
private class ThreadSafeInstrumentValues
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
{
private readonly ThreadLocal<Dictionary<int, InstrumentsValues>> threadIdToInstrumentValues = new(() =>
{
return new Dictionary<int, InstrumentsValues>();
});

internal double GetMemoryUsage()
{
if (!this.threadIdToInstrumentValues.Value.ContainsKey(Environment.CurrentManagedThreadId))
{
this.threadIdToInstrumentValues.Value.Add(Environment.CurrentManagedThreadId, new InstrumentsValues());
}

this.threadIdToInstrumentValues.Value.TryGetValue(Environment.CurrentManagedThreadId, out var instrumentValues);
return instrumentValues.GetMemoryUsage();
}

internal double GetVirtualMemoryUsage()
{
if (!this.threadIdToInstrumentValues.Value.ContainsKey(Environment.CurrentManagedThreadId))
{
this.threadIdToInstrumentValues.Value.Add(Environment.CurrentManagedThreadId, new InstrumentsValues());
}

this.threadIdToInstrumentValues.Value.TryGetValue(Environment.CurrentManagedThreadId, out var instrumentsValues);
return instrumentsValues.GetVirtualMemoryUsage();
}
}

private class InstrumentsValues
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
{
private readonly Diagnostics.Process currentProcess = Diagnostics.Process.GetCurrentProcess();
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
private double? memoryUsage;
private double? virtualMemoryUsage;

internal InstrumentsValues()
{
this.memoryUsage = null;
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
this.virtualMemoryUsage = null;
}

internal double GetMemoryUsage()
{
if (!this.memoryUsage.HasValue)
utpilla marked this conversation as resolved.
Show resolved Hide resolved
{
this.Snapshot();
}

var value = (double)this.memoryUsage;
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
this.memoryUsage = null;
return value;
}

internal double GetVirtualMemoryUsage()
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
{
if (!this.virtualMemoryUsage.HasValue)
{
this.Snapshot();
}

var value = (double)this.virtualMemoryUsage;
Yun-Ting marked this conversation as resolved.
Show resolved Hide resolved
this.virtualMemoryUsage = null;
return value;
}

private void Snapshot()
{
this.currentProcess.Refresh();
this.memoryUsage = this.currentProcess.WorkingSet64;
this.virtualMemoryUsage = this.currentProcess.PagedMemorySize64;
}
}
}