Add stack trace and object min/max size limits.
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Tue, 16 May 2023 15:50:33 +0000 (18:50 +0300)
committerGleb Balykov/Advanced System SW Lab /SRR/Staff Engineer/Samsung Electronics <g.balykov@samsung.com>
Mon, 22 May 2023 18:24:57 +0000 (21:24 +0300)
README.md
src/config/configurationmanager.cpp
src/config/profilerconfig.cpp
src/config/profilerconfig.h
src/info/objectinfo.cpp
src/info/objectinfo.h
src/trace/executiontrace.cpp
src/trace/memorytrace.cpp
src/tracelog/tracelog.cpp

index 200aea35c9f49e86126172ab1b4f8639a5be6a07..ad29944ed8180777d1782e0496f75ea13cd3dba8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -138,6 +138,20 @@ dumped (only timestamp of execution and configuration parameters is stored).
         `PROF_MEMORY_TRACE` turned on in conjunction for sampling mode (see
         below).
 
+      - `PROF_MEMORY_MIN_SIZE_LIMIT` - collect data about allocations for objects
+        with size more or equal `PROF_MEMORY_MIN_SIZE_LIMIT` amount of bytes.
+        Default value is `0` (limit is disabled).
+
+      - `PROF_MEMORY_MAX_SIZE_LIMIT` - collect data about allocations for objects
+        with size less or equal `PROF_MEMORY_MAX_SIZE_LIMIT` amount of bytes.
+        Must be greater or equal to `PROF_MEMORY_MIN_SIZE_LIMIT` or will be disabled.
+        Default value is `0` (limit is disabled).
+
+  - `PROF_STACK_DEPTH_LIMIT` - track changes of execution stack for first
+    `PROF_STACK_DEPTH_LIMIT` frames only. Default value is `0` (limit is disabled).
+    _Current limitation: `PROF_EXECUTION_TRACE` or `PROF_MEMORY_TRACE`
+    should also be enabled to use this options._
+
   - `PROF_GC_TRACE` - enables tracking of GC events. Value of this options is
     used as default for following options. However, each following
     option can be turned on or off manually. `PROF_GC_TRACE` is defaulted to
index 85bec8e99a15542ba740dddf417dc4d4bb505f03..78ef6942f57bb801ddb0e2eddaa85b988d6d152d 100644 (file)
@@ -157,6 +157,7 @@ void ConfigurationManager::FetchConfig(ProfilerConfig &config) const
     FetchValue("PROF_HIGH_GRAN",     new_config.HighGranularityEnabled);
     FetchValue("PROF_DELAYED_START", new_config.TracingSuspendedOnStart);
     FetchValue("PROF_LINE_TRACE",    new_config.LineTraceEnabled);
+    FetchValue("PROF_STACK_DEPTH_LIMIT", new_config.StackDepthLimit);
 
     bool CpuTraceEnabled;
     if (FetchValue("PROF_CPU_TRACE", CpuTraceEnabled))
@@ -182,6 +183,8 @@ void ConfigurationManager::FetchConfig(ProfilerConfig &config) const
     }
 
     FetchValue("PROF_STACK_TRACK",      new_config.StackTrackingEnabled);
+    FetchValue("PROF_MEMORY_MIN_SIZE_LIMIT", new_config.MemoryMinSizeLimit);
+    FetchValue("PROF_MEMORY_MAX_SIZE_LIMIT", new_config.MemoryMaxSizeLimit);
 
     bool GcTraceEnabled;
     if (FetchValue("PROF_GC_TRACE", GcTraceEnabled))
index 795e870edaaadcfd82a9ccde5ed5fdf66f475386..0b3c69cca8f4162742c416b2e04522f987888bab 100644 (file)
@@ -28,12 +28,15 @@ ProfilerConfig::ProfilerConfig()
     , HighGranularityEnabled(true)
     , TracingSuspendedOnStart(false)
     , LineTraceEnabled(false)
+    , StackDepthLimit(0)
     , CpuTraceProcessEnabled(false)
     , CpuTraceThreadEnabled(false)
     , CpuTraceTimeoutMs(10)
     , ExecutionTraceEnabled(false)
     , MemoryTraceEnabled(false)
     , StackTrackingEnabled(false)
+    , MemoryMinSizeLimit(0)
+    , MemoryMaxSizeLimit(0)
     , GcGenerationBoundsTraceEnabled(false)
     , GcAllocTableTraceEnabled(false)
 {}
@@ -130,6 +133,12 @@ std::vector<std::string> ProfilerConfig::Verify()
             warnings.push_back(
                 "line tracing requires execution or memory tracing");
         }
+
+        if (StackDepthLimit != 0)
+        {
+            warnings.push_back(
+                "stack trace depth limit requires execution or memory tracing");
+        }
     }
 
     if (!MemoryTraceEnabled)
@@ -139,6 +148,16 @@ std::vector<std::string> ProfilerConfig::Verify()
             warnings.push_back("stack tracking is memory tracing option");
         }
 
+        if (MemoryMinSizeLimit != 0)
+        {
+            warnings.push_back("memory min size limit is memory tracing option");
+        }
+
+        if (MemoryMaxSizeLimit != 0)
+        {
+            warnings.push_back("memory max size limit is memory tracing option");
+        }
+
         if (GcGenerationBoundsTraceEnabled)
         {
             warnings.push_back(
@@ -152,6 +171,12 @@ std::vector<std::string> ProfilerConfig::Verify()
         }
     }
 
+    if (MemoryMaxSizeLimit && MemoryMinSizeLimit > MemoryMaxSizeLimit)
+    {
+        MemoryMaxSizeLimit = 0;
+        warnings.push_back("memory max size limit must be greater or equal to memory min size limit, memory max size limit disabled");
+    }
+
     return warnings;
 }
 
index e44c7aa90c3b2b52778950eccfaf703162d8bb62..83c679ed91ca512626302edfaf2e056f302c5a8b 100644 (file)
@@ -51,6 +51,7 @@ struct ProfilerConfig
     bool             HighGranularityEnabled;
     bool             TracingSuspendedOnStart;
     bool             LineTraceEnabled;
+    unsigned long    StackDepthLimit;
 
     //
     // CPU Trace features.
@@ -72,6 +73,8 @@ struct ProfilerConfig
 
     bool             MemoryTraceEnabled;
     bool             StackTrackingEnabled;
+    unsigned long    MemoryMinSizeLimit;
+    unsigned long    MemoryMaxSizeLimit;
     bool             GcGenerationBoundsTraceEnabled;
     bool             GcAllocTableTraceEnabled;
 
index dbda85b2dc37a28ef5a3ab0a5bc59d5b3398494e..46d04f715b8e63f91ff842c7627b54646835c073 100644 (file)
@@ -153,13 +153,19 @@ HRESULT ObjectInfo::Initialize(
     _ASSERTE(this->id != 0);
     const ProfilerInfo &info = profiler.GetProfilerInfo();
 
-    hr = this->InitializeTypeFromClassId(profiler, storage, classId);
+    hr = this->InitializeSize(profiler, info);
     if (FAILED(hr) && SUCCEEDED(hrReturn))
     {
         hrReturn = hr;
     }
 
-    hr = this->InitializeSize(profiler, info);
+    if (this->size < profiler.GetConfig().MemoryMinSizeLimit ||
+        (profiler.GetConfig().MemoryMaxSizeLimit && this->size > profiler.GetConfig().MemoryMaxSizeLimit))
+    {
+        return hrReturn;
+    }
+
+    hr = this->InitializeTypeFromClassId(profiler, storage, classId);
     if (FAILED(hr) && SUCCEEDED(hrReturn))
     {
         hrReturn = hr;
index 7aae402cfcdc4da0a99881ef793e474053f9a487..97b862546059e619fa2bc9f1f948382843c44435 100644 (file)
@@ -49,11 +49,11 @@ private:
         const Profiler &profiler,
         const ProfilerInfo &info) noexcept;
 
-public:
     HRESULT Initialize(
         const Profiler &profiler,
         ClassStorage &storage) noexcept;
 
+public:
     HRESULT Initialize(
         const Profiler &profiler,
         ClassStorage &storage,
index 6e38da0a404956d55b5636ed1e4e1a7fac039016..fe4e08c8e754161b6360ad3b3d7bb4862b397569 100644 (file)
@@ -21,6 +21,9 @@
 
 #include "traceinlines.h"
 
+// Related to PROF_STACK_DEPTH_LIMIT.
+thread_local unsigned long SkippedTopFramesCount = 0;
+
 EXTERN_C UINT_PTR __stdcall FunctionIDMapStub(
     FunctionID funcId,
     void *clientData,
@@ -320,6 +323,13 @@ void ExecutionTrace::RestoreManagedIP(
 
 void ExecutionTrace::UpdateCallStackPush(const FunctionInfo &funcInfo) noexcept
 {
+    if (m_profiler.GetConfig().StackDepthLimit && // In case `StackDepthLimit` == 0 limit is disabled.
+        m_profiler.GetCommonTrace().GetThreadInfo()->eventChannel.GetStackSize() > m_profiler.GetConfig().StackDepthLimit)
+    {
+        SkippedTopFramesCount++;
+        return;
+    }
+
     SamplingSharedState state = {};
     state.stackWillBeChanged = true;
     m_profiler.GetCommonTrace().InterruptSampling(
@@ -342,6 +352,13 @@ void ExecutionTrace::UpdateCallStackPush(const FunctionInfo &funcInfo) noexcept
 void ExecutionTrace::UpdateCallStackPush(
     const FunctionInfo &funcInfo, UINT_PTR prevIP) noexcept
 {
+    if (m_profiler.GetConfig().StackDepthLimit && // In case `StackDepthLimit` == 0 limit is disabled.
+        m_profiler.GetCommonTrace().GetThreadInfo()->eventChannel.GetStackSize() > m_profiler.GetConfig().StackDepthLimit)
+    {
+        SkippedTopFramesCount++;
+        return;
+    }
+
     SamplingSharedState state = {};
     state.stackWillBeChanged = true;
     m_profiler.GetCommonTrace().InterruptSampling(
@@ -373,6 +390,12 @@ void ExecutionTrace::UpdateCallStackPush(
 
 void ExecutionTrace::UpdateCallStackPop() noexcept
 {
+    if (SkippedTopFramesCount)
+    {
+        SkippedTopFramesCount--;
+        return;
+    }
+
     SamplingSharedState state = {};
     state.stackWillBeChanged = true;
     bool needPrintWarning = false;
index 38799b3ff8d458b24c7999f326bceb99198371d0..5217f3c8fd93c3036ca7b770acff37f53858148f 100644 (file)
@@ -155,6 +155,12 @@ HRESULT MemoryTrace::InitAllocInfoByTypes(AllocTable &allocInfoByTypes) noexcept
                 );
             }
 
+            if (objInfo.size < m_profiler.GetConfig().MemoryMinSizeLimit ||
+                (m_profiler.GetConfig().MemoryMaxSizeLimit && objInfo.size > m_profiler.GetConfig().MemoryMaxSizeLimit))
+            {
+                continue;
+            }
+
             _ASSERTE(objInfo.type != nullptr);
             if (objInfo.type->needPrintLoadFinished)
             {
@@ -208,6 +214,12 @@ HRESULT MemoryTrace::ObjectAllocated(
             );
         }
 
+        if (objInfo.size < m_profiler.GetConfig().MemoryMinSizeLimit ||
+            (m_profiler.GetConfig().MemoryMaxSizeLimit && objInfo.size > m_profiler.GetConfig().MemoryMaxSizeLimit))
+        {
+            return hr;
+        }
+
         _ASSERTE(objInfo.type != nullptr);
         if (objInfo.type->needPrintLoadFinished)
         {
index 2cd6a9f07dbdbbb0106dcfa99f1fb6aaedba3e20..a468bc460978ad23a4b9d1272461e0ffd74f945c 100644 (file)
@@ -150,12 +150,15 @@ public:
         m_tracefmt.log("prf cfg", g_tls_ss).str("HighGranularityEnabled").config(config.HighGranularityEnabled).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("TracingSuspendedOnStart").config(config.TracingSuspendedOnStart).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("LineTraceEnabled").config(config.LineTraceEnabled).end();
+        m_tracefmt.log("prf cfg", g_tls_ss).str("StackDepthLimit").config(config.StackDepthLimit).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("CpuTraceProcessEnabled").config(config.CpuTraceProcessEnabled).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("CpuTraceThreadEnabled").config(config.CpuTraceThreadEnabled).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("CpuTraceTimeoutMs").config(config.CpuTraceTimeoutMs).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("ExecutionTraceEnabled").config(config.ExecutionTraceEnabled).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("MemoryTraceEnabled").config(config.MemoryTraceEnabled).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("StackTrackingEnabled").config(config.StackTrackingEnabled).end();
+        m_tracefmt.log("prf cfg", g_tls_ss).str("MemoryMinSizeLimit").config(config.MemoryMinSizeLimit).end();
+        m_tracefmt.log("prf cfg", g_tls_ss).str("MemoryMaxSizeLimit").config(config.MemoryMaxSizeLimit).end();
         m_tracefmt.log("prf cfg", g_tls_ss).str("GcAllocTableTraceEnabled").config(config.GcAllocTableTraceEnabled).end();
         AddTLSDataToQueue();
     }