Skip to content

Commit 48f980e

Browse files
committed
Add metric on lock failure for IsManaged
1 parent 0508822 commit 48f980e

4 files changed

Lines changed: 26 additions & 6 deletions

File tree

profiler/src/ProfilerEngine/Datadog.Profiler.Native/CorProfilerCallback.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1567,7 +1567,7 @@ HRESULT STDMETHODCALLTYPE CorProfilerCallback::Initialize(IUnknown* corProfilerI
15671567
// Use managed code cache
15681568
if (_pConfiguration->UseManagedCodeCache())
15691569
{
1570-
_managedCodeCache = std::make_unique<ManagedCodeCache>(_pCorProfilerInfo);
1570+
_managedCodeCache = std::make_unique<ManagedCodeCache>(_pCorProfilerInfo, _metricsRegistry);
15711571
if (!_managedCodeCache->Initialize())
15721572
{
15731573
Log::Error("Failed to initialize managed code cache. The profiler will not run.");

profiler/src/ProfilerEngine/Datadog.Profiler.Native/ManagedCodeCache.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "ManagedCodeCache.h"
55

66
#include "Configuration.h"
7+
#include "CounterMetric.h"
8+
#include "MetricsRegistry.h"
79

810
#include <algorithm>
911
#include <chrono>
@@ -88,8 +90,9 @@ struct IMAGE_NT_HEADERS_GENERIC
8890
WORD Magic;
8991
};
9092

91-
ManagedCodeCache::ManagedCodeCache(ICorProfilerInfo4* pProfilerInfo)
92-
: _profilerInfo(pProfilerInfo)
93+
ManagedCodeCache::ManagedCodeCache(ICorProfilerInfo4* pProfilerInfo, MetricsRegistry& metricsRegistry)
94+
: _profilerInfo(pProfilerInfo),
95+
_lockFailureMetric(metricsRegistry.GetOrRegister<CounterMetric>("dotnet_managed_code_cache_lock_failures"))
9396
{
9497
}
9598

@@ -239,7 +242,14 @@ std::optional<bool> ManagedCodeCache::IsManaged(std::uintptr_t ip) const noexcep
239242
// Best effort to identify an instruction pointer. When called from a signal
240243
// handler, IsManagedImpl uses a time-based lock acquire (bounded wait) and
241244
// returns std::nullopt if a lock cannot be acquired within the timeout.
242-
return IsManagedImpl(ip);
245+
auto result = IsManagedImpl(ip);
246+
if (!result.has_value())
247+
{
248+
// Lock could not be acquired within the timeout: record it. Incr() is an
249+
// atomic increment, so this is safe to call from a signal handler.
250+
_lockFailureMetric->Incr();
251+
}
252+
return result;
243253
}
244254

245255
std::optional<bool> ManagedCodeCache::IsManagedImpl(std::uintptr_t ip) const noexcept

profiler/src/ProfilerEngine/Datadog.Profiler.Native/ManagedCodeCache.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#pragma once
55

66
#include <atomic>
7+
#include <memory>
78
#include <vector>
89
#include <unordered_map>
910
#include <unordered_set>
@@ -17,6 +18,9 @@
1718
#include "cor.h"
1819
#include "corprof.h"
1920

21+
class CounterMetric;
22+
class MetricsRegistry;
23+
2024
// Represents a single contiguous code range
2125
struct CodeRange {
2226
UINT_PTR startAddress;
@@ -73,7 +77,7 @@ class ManagedCodeCache {
7377
public:
7478
static constexpr FunctionID InvalidFunctionId = -1;
7579

76-
explicit ManagedCodeCache(ICorProfilerInfo4* pProfilerInfo);
80+
ManagedCodeCache(ICorProfilerInfo4* pProfilerInfo, MetricsRegistry& metricsRegistry);
7781
~ManagedCodeCache();
7882

7983
// Signal-safe lookup methods (no allocation)
@@ -168,6 +172,10 @@ class ManagedCodeCache {
168172
// Profiler interface (ICorProfilerInfo4 is available in .NET Framework 4.5+)
169173
ICorProfilerInfo4* _profilerInfo;
170174

175+
// Counts how many times IsManaged failed to acquire a lock within the timeout
176+
// (signal-handler read path backing off instead of blocking).
177+
std::shared_ptr<CounterMetric> _lockFailureMetric;
178+
171179
std::optional<FunctionID> GetFunctionIdImpl(std::uintptr_t ip) const noexcept;
172180
std::optional<bool> IsCodeInR2RModule(std::uintptr_t ip, bool signalSafe) const noexcept;
173181
std::optional<FunctionID> GetFunctionFromIP_Original(std::uintptr_t ip) noexcept;

profiler/test/Datadog.Profiler.Native.Tests/ManagedCodeCacheTest.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "gtest/gtest.h"
55
#include "gmock/gmock.h"
66
#include "ManagedCodeCache.h"
7+
#include "MetricsRegistry.h"
78
#include "MockProfilerInfo.h"
89

910
#include <thread>
@@ -15,11 +16,12 @@ using namespace testing;
1516
class ManagedCodeCacheTest : public Test {
1617
protected:
1718
MockProfilerInfo* mockProfiler;
19+
MetricsRegistry metricsRegistry;
1820
std::unique_ptr<ManagedCodeCache> cache;
1921

2022
void SetUp() override {
2123
mockProfiler = new MockProfilerInfo();
22-
cache = std::make_unique<ManagedCodeCache>(mockProfiler);
24+
cache = std::make_unique<ManagedCodeCache>(mockProfiler, metricsRegistry);
2325
cache->Initialize();
2426
}
2527

0 commit comments

Comments
 (0)