This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git


The following commit(s) were added to refs/heads/main by this push:
     new d357bdef7a Support keep trace profiling when cross-thread (#479)
d357bdef7a is described below

commit d357bdef7a3f1f9e78e6a8e29b372f3270e1acc2
Author: mrproliu <741550...@qq.com>
AuthorDate: Tue Mar 14 17:55:28 2023 +0800

    Support keep trace profiling when cross-thread (#479)
---
 CHANGES.md                                         |   1 +
 .../skywalking/apm/agent/core/conf/Config.java     |   7 +-
 .../apm/agent/core/context/ContextSnapshot.java    |   6 +-
 .../agent/core/context/IgnoredTracerContext.java   |   5 +-
 .../apm/agent/core/context/TracingContext.java     |  12 ++-
 .../agent/core/profile/ProfileStatusContext.java   | 110 +++++++++++++++++++++
 .../agent/core/profile/ProfileStatusReference.java |  69 -------------
 .../core/profile/ProfileTaskExecutionContext.java  |  49 +++++----
 .../core/profile/ProfileTaskExecutionService.java  |  20 +++-
 .../apm/agent/core/profile/ThreadProfiler.java     |  16 +--
 .../agent/core/context/MockContextSnapshot.java    |   4 +-
 apm-sniffer/config/agent.config                    |   4 +-
 .../service-agent/java-agent/configurations.md     |   1 +
 13 files changed, 196 insertions(+), 108 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 3e7f719c0e..a238a5876e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -20,6 +20,7 @@ Release Notes.
 * Adapt Armeria's plugins to the latest version 1.22.x
 * Fix tomcat-10x-plugin and add test case to support tomcat7.x-8.x-9.x.
 * Fix thrift plugin generate duplicate traceid when `sendBase` error occurs
+* Support keep trace profiling when cross-thread.
 
 #### Documentation
 * Update docs of Tracing APIs, reorganize the API docs into six parts.
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
index 861a0ef01f..2ff91a6de4 100755
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
@@ -241,10 +241,15 @@ public class Config {
         public static boolean ACTIVE = true;
 
         /**
-         * Parallel monitor segment count
+         * Parallel monitor endpoint thread count
          */
         public static int MAX_PARALLEL = 5;
 
+        /**
+         * Max monitoring sub-tasks count of one single endpoint access
+         */
+        public static int MAX_ACCEPT_SUB_PARALLEL = 5;
+
         /**
          * Max monitor segment time(minutes), if current segment monitor time 
out of limit, then stop it.
          */
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextSnapshot.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextSnapshot.java
index 9db53a1791..3455e6698d 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextSnapshot.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextSnapshot.java
@@ -20,6 +20,7 @@ package org.apache.skywalking.apm.agent.core.context;
 
 import lombok.Getter;
 import org.apache.skywalking.apm.agent.core.context.ids.DistributedTraceId;
+import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
 
 /**
  * The <code>ContextSnapshot</code> is a snapshot for current context. The 
snapshot carries the info for building
@@ -34,19 +35,22 @@ public class ContextSnapshot {
 
     private CorrelationContext correlationContext;
     private ExtensionContext extensionContext;
+    private ProfileStatusContext profileStatusContext;
 
     ContextSnapshot(String traceSegmentId,
                     int spanId,
                     DistributedTraceId primaryTraceId,
                     String parentEndpoint,
                     CorrelationContext correlationContext,
-                    ExtensionContext extensionContext) {
+                    ExtensionContext extensionContext,
+                    ProfileStatusContext profileStatusContext) {
         this.traceSegmentId = traceSegmentId;
         this.spanId = spanId;
         this.traceId = primaryTraceId;
         this.parentEndpoint = parentEndpoint;
         this.correlationContext = correlationContext.clone();
         this.extensionContext = extensionContext.clone();
+        this.profileStatusContext = profileStatusContext.clone();
     }
 
     public boolean isFromCurrent() {
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java
index 5433b14176..67fabd3e0a 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java
@@ -22,6 +22,7 @@ import java.util.LinkedList;
 import java.util.List;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
 import org.apache.skywalking.apm.agent.core.context.trace.NoopSpan;
+import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
 
 /**
  * The <code>IgnoredTracerContext</code> represent a context should be 
ignored. So it just maintains the stack with an
@@ -35,6 +36,7 @@ public class IgnoredTracerContext implements 
AbstractTracerContext {
 
     private final CorrelationContext correlationContext;
     private final ExtensionContext extensionContext;
+    private final ProfileStatusContext profileStatusContext;
 
     private int stackDepth;
 
@@ -42,6 +44,7 @@ public class IgnoredTracerContext implements 
AbstractTracerContext {
         this.stackDepth = 0;
         this.correlationContext = new CorrelationContext();
         this.extensionContext = new ExtensionContext();
+        this.profileStatusContext = ProfileStatusContext.createWithNone();
     }
 
     @Override
@@ -56,7 +59,7 @@ public class IgnoredTracerContext implements 
AbstractTracerContext {
 
     @Override
     public ContextSnapshot capture() {
-        return new ContextSnapshot(null, -1, null, null, correlationContext, 
extensionContext);
+        return new ContextSnapshot(null, -1, null, null, correlationContext, 
extensionContext, profileStatusContext);
     }
 
     @Override
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
index 574ccd6a46..305672bb2a 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java
@@ -41,7 +41,7 @@ import 
org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
 import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
 import org.apache.skywalking.apm.agent.core.logging.api.ILog;
 import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
-import org.apache.skywalking.apm.agent.core.profile.ProfileStatusReference;
+import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
 import 
org.apache.skywalking.apm.agent.core.profile.ProfileTaskExecutionService;
 import org.apache.skywalking.apm.util.StringUtil;
 
@@ -106,7 +106,7 @@ public class TracingContext implements 
AbstractTracerContext {
     /**
      * profile status
      */
-    private final ProfileStatusReference profileStatus;
+    private final ProfileStatusContext profileStatus;
     @Getter(AccessLevel.PACKAGE)
     private final CorrelationContext correlationContext;
     @Getter(AccessLevel.PACKAGE)
@@ -213,7 +213,8 @@ public class TracingContext implements 
AbstractTracerContext {
             getPrimaryTraceId(),
             primaryEndpoint.getName(),
             this.correlationContext,
-            this.extensionContext
+            this.extensionContext,
+            this.profileStatus
         );
 
         return snapshot;
@@ -234,6 +235,9 @@ public class TracingContext implements 
AbstractTracerContext {
             this.correlationContext.continued(snapshot);
             this.extensionContext.continued(snapshot);
             this.extensionContext.handle(this.activeSpan());
+            if (this.profileStatus.continued(snapshot)) {
+                PROFILE_TASK_EXECUTION_SERVICE.continueProfiling(this, 
this.segment.getTraceSegmentId());
+            }
         }
     }
 
@@ -571,7 +575,7 @@ public class TracingContext implements 
AbstractTracerContext {
         return this.createTime;
     }
 
-    public ProfileStatusReference profileStatus() {
+    public ProfileStatusContext profileStatus() {
         return this.profileStatus;
     }
 
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusContext.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusContext.java
new file mode 100644
index 0000000000..671216d4d9
--- /dev/null
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusContext.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.core.profile;
+
+import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.TracingContext;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Wrapper {@link ProfileStatus}, make sure {@link 
org.apache.skywalking.apm.agent.core.context.TracingContext} with {@link 
ThreadProfiler} have same reference with {@link ProfileStatus},
+ * And only the profile module could change the status
+ */
+public class ProfileStatusContext {
+
+    private volatile ProfileStatus status;
+    private volatile long firstSegmentCreateTime;
+    private volatile AtomicInteger subThreadProfilingCount;
+
+    private ProfileStatusContext(ProfileStatus status, long 
firstSegmentCreateTime, AtomicInteger subThreadProfilingCount) {
+        this.status = status;
+        this.firstSegmentCreateTime = firstSegmentCreateTime;
+        this.subThreadProfilingCount = subThreadProfilingCount;
+    }
+
+    /**
+     * Create with not watching
+     */
+    public static ProfileStatusContext createWithNone() {
+        return new ProfileStatusContext(ProfileStatus.NONE, 0, null);
+    }
+
+    /**
+     * Create with pending to profile
+     */
+    public static ProfileStatusContext createWithPending(long 
firstSegmentCreateTime) {
+        return new ProfileStatusContext(ProfileStatus.PENDING, 
firstSegmentCreateTime, new AtomicInteger(0));
+    }
+
+    public ProfileStatus get() {
+        return this.status;
+    }
+
+    public long firstSegmentCreateTime() {
+        return this.firstSegmentCreateTime;
+    }
+
+    /**
+     * The profile monitoring is watching, wait for some profile conditions.
+     */
+    public boolean isBeingWatched() {
+        return this.status != ProfileStatus.NONE;
+    }
+
+    public boolean isProfiling() {
+        return this.status == ProfileStatus.PROFILING;
+    }
+
+    public ProfileStatusContext clone() {
+        return new ProfileStatusContext(this.status, 
this.firstSegmentCreateTime, this.subThreadProfilingCount);
+    }
+
+    /**
+     * Continued profile status context
+     * @return is needs to keep profile
+     */
+    public boolean continued(ContextSnapshot snapshot) {
+        this.status = snapshot.getProfileStatusContext().get();
+        this.firstSegmentCreateTime = 
snapshot.getProfileStatusContext().firstSegmentCreateTime();
+        this.subThreadProfilingCount = 
snapshot.getProfileStatusContext().subThreadProfilingCount;
+        return this.isBeingWatched() &&
+            // validate is reach the count of sub-thread
+            this.subThreadProfilingCount != null &&
+            this.subThreadProfilingCount.incrementAndGet() <= 
Config.Profile.MAX_ACCEPT_SUB_PARALLEL;
+    }
+
+    /**
+     * Update status, only access with profile module
+     */
+    void updateStatus(ProfileStatus status, TracingContext tracingContext) {
+        this.status = status;
+        if (this.firstSegmentCreateTime == 0 && tracingContext != null) {
+            this.firstSegmentCreateTime = tracingContext.createTime();
+        }
+    }
+
+    void updateStatus(ProfileStatusContext statusContext) {
+        this.status = statusContext.get();
+        this.firstSegmentCreateTime = statusContext.firstSegmentCreateTime();
+        this.subThreadProfilingCount = statusContext.subThreadProfilingCount;
+    }
+
+}
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java
deleted file mode 100644
index 7d1149fc7a..0000000000
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.agent.core.profile;
-
-/**
- * Wrapper {@link ProfileStatus}, make sure {@link 
org.apache.skywalking.apm.agent.core.context.TracingContext} with {@link 
ThreadProfiler} have same reference with {@link ProfileStatus},
- * And only the profile module could change the status
- */
-public class ProfileStatusReference {
-
-    private volatile ProfileStatus status;
-
-    private ProfileStatusReference(ProfileStatus status) {
-        this.status = status;
-    }
-
-    /**
-     * Create with not watching
-     */
-    public static ProfileStatusReference createWithNone() {
-        return new ProfileStatusReference(ProfileStatus.NONE);
-    }
-
-    /**
-     * Create with pending to profile
-     */
-    public static ProfileStatusReference createWithPending() {
-        return new ProfileStatusReference(ProfileStatus.PENDING);
-    }
-
-    public ProfileStatus get() {
-        return this.status;
-    }
-
-    /**
-     * The profile monitoring is watching, wait for some profile conditions.
-     */
-    public boolean isBeingWatched() {
-        return this.status != ProfileStatus.NONE;
-    }
-
-    public boolean isProfiling() {
-        return this.status == ProfileStatus.PROFILING;
-    }
-
-    /**
-     * Update status, only access with profile module
-     */
-    void updateStatus(ProfileStatus status) {
-        this.status = status;
-    }
-
-}
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
index 7cee797045..e53090b5f7 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionContext.java
@@ -34,8 +34,8 @@ public class ProfileTaskExecutionContext {
     // task data
     private final ProfileTask task;
 
-    // record current profiling count, use this to check has available profile 
slot
-    private final AtomicInteger currentProfilingCount = new AtomicInteger(0);
+    // record current first endpoint profiling count, use this to check has 
available profile slot
+    private final AtomicInteger currentEndpointProfilingCount = new 
AtomicInteger(0);
 
     // profiling segment slot
     private volatile AtomicReferenceArray<ThreadProfiler> 
profilingSegmentSlots;
@@ -48,7 +48,7 @@ public class ProfileTaskExecutionContext {
 
     public ProfileTaskExecutionContext(ProfileTask task) {
         this.task = task;
-        profilingSegmentSlots = new 
AtomicReferenceArray<>(Config.Profile.MAX_PARALLEL);
+        profilingSegmentSlots = new 
AtomicReferenceArray<>(Config.Profile.MAX_PARALLEL * 
(Config.Profile.MAX_ACCEPT_SUB_PARALLEL + 1));
     }
 
     /**
@@ -72,39 +72,52 @@ public class ProfileTaskExecutionContext {
      *
      * @return is add profile success
      */
-    public ProfileStatusReference attemptProfiling(TracingContext 
tracingContext,
-                                                   String traceSegmentId,
-                                                   String firstSpanOPName) {
-        // check has available slot
-        final int usingSlotCount = currentProfilingCount.get();
-        if (usingSlotCount >= Config.Profile.MAX_PARALLEL) {
-            return ProfileStatusReference.createWithNone();
+    public ProfileStatusContext attemptProfiling(TracingContext tracingContext,
+                                                 String traceSegmentId,
+                                                 String firstSpanOPName) {
+        // check has limited the max parallel profiling count
+        final int profilingEndpointCount = currentEndpointProfilingCount.get();
+        if (profilingEndpointCount >= Config.Profile.MAX_PARALLEL) {
+            return ProfileStatusContext.createWithNone();
         }
 
         // check first operation name matches
         if (!Objects.equals(task.getFirstSpanOPName(), firstSpanOPName)) {
-            return ProfileStatusReference.createWithNone();
+            return ProfileStatusContext.createWithNone();
         }
 
         // if out limit started profiling count then stop add profiling
         if (totalStartedProfilingCount.get() > task.getMaxSamplingCount()) {
-            return ProfileStatusReference.createWithNone();
+            return ProfileStatusContext.createWithNone();
         }
 
         // try to occupy slot
-        if (!currentProfilingCount.compareAndSet(usingSlotCount, 
usingSlotCount + 1)) {
-            return ProfileStatusReference.createWithNone();
+        if 
(!currentEndpointProfilingCount.compareAndSet(profilingEndpointCount, 
profilingEndpointCount + 1)) {
+            return ProfileStatusContext.createWithNone();
         }
 
+        ThreadProfiler profiler;
+        if ((profiler = addProfilingThread(tracingContext, traceSegmentId)) != 
null) {
+            return profiler.profilingStatus();
+        }
+        return ProfileStatusContext.createWithNone();
+    }
+
+    public boolean continueProfiling(TracingContext tracingContext, String 
traceSegmentId) {
+        return addProfilingThread(tracingContext, traceSegmentId) != null;
+    }
+
+    private ThreadProfiler addProfilingThread(TracingContext tracingContext, 
String traceSegmentId) {
         final ThreadProfiler threadProfiler = new ThreadProfiler(
             tracingContext, traceSegmentId, Thread.currentThread(), this);
         int slotLength = profilingSegmentSlots.length();
         for (int slot = 0; slot < slotLength; slot++) {
             if (profilingSegmentSlots.compareAndSet(slot, null, 
threadProfiler)) {
-                return threadProfiler.profilingStatus();
+                return threadProfiler;
             }
         }
-        return ProfileStatusReference.createWithNone();
+        // add profiling thread failure, so ignore it
+        return null;
     }
 
     /**
@@ -118,7 +131,7 @@ public class ProfileTaskExecutionContext {
 
         // update profiling status
         tracingContext.profileStatus()
-                      .updateStatus(attemptProfiling(tracingContext, 
traceSegmentId, firstSpanOPName).get());
+                      .updateStatus(attemptProfiling(tracingContext, 
traceSegmentId, firstSpanOPName));
     }
 
     /**
@@ -134,7 +147,7 @@ public class ProfileTaskExecutionContext {
 
                 // setting stop running
                 currentProfiler.stopProfiling();
-                currentProfilingCount.addAndGet(-1);
+                currentEndpointProfilingCount.addAndGet(-1);
                 break;
             }
         }
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
index f79ccb07c9..796664b63b 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileTaskExecutionService.java
@@ -90,18 +90,30 @@ public class ProfileTaskExecutionService implements 
BootService, TracingThreadLi
     /**
      * check and add {@link TracingContext} profiling
      */
-    public ProfileStatusReference addProfiling(TracingContext tracingContext,
-                                               String traceSegmentId,
-                                               String firstSpanOPName) {
+    public ProfileStatusContext addProfiling(TracingContext tracingContext,
+                                             String traceSegmentId,
+                                             String firstSpanOPName) {
         // get current profiling task, check need profiling
         final ProfileTaskExecutionContext executionContext = 
taskExecutionContext.get();
         if (executionContext == null) {
-            return ProfileStatusReference.createWithNone();
+            return ProfileStatusContext.createWithNone();
         }
 
         return executionContext.attemptProfiling(tracingContext, 
traceSegmentId, firstSpanOPName);
     }
 
+    /**
+     * continue profiling task when cross-thread
+     */
+    public void continueProfiling(TracingContext tracingContext, String 
traceSegmentId) {
+        final ProfileTaskExecutionContext executionContext = 
taskExecutionContext.get();
+        if (executionContext == null) {
+            return;
+        }
+
+        executionContext.continueProfiling(tracingContext, traceSegmentId);
+    }
+
     /**
      * Re-check current trace need profiling, in case that third-party plugins 
change the operation name.
      */
diff --git 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
index e2425eb10c..322b01b9f7 100644
--- 
a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
+++ 
b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ThreadProfiler.java
@@ -40,7 +40,7 @@ public class ThreadProfiler {
     private long profilingMaxTimeMills;
 
     // after min duration threshold check, it will start dump
-    private final ProfileStatusReference profilingStatus;
+    private final ProfileStatusContext profilingStatus;
     // thread dump sequence
     private int dumpSequence = 0;
 
@@ -51,10 +51,10 @@ public class ThreadProfiler {
         this.profilingThread = profilingThread;
         this.executionContext = executionContext;
         if (tracingContext.profileStatus() == null) {
-            this.profilingStatus = ProfileStatusReference.createWithPending();
+            this.profilingStatus = 
ProfileStatusContext.createWithPending(tracingContext().createTime());
         } else {
             this.profilingStatus = tracingContext.profileStatus();
-            this.profilingStatus.updateStatus(ProfileStatus.PENDING);
+            this.profilingStatus.updateStatus(ProfileStatus.PENDING, 
tracingContext);
         }
         this.profilingMaxTimeMills = 
TimeUnit.MINUTES.toMillis(Config.Profile.MAX_DURATION);
     }
@@ -63,10 +63,10 @@ public class ThreadProfiler {
      * If tracing start time greater than {@link 
ProfileTask#getMinDurationThreshold()}, then start to profiling trace
      */
     public void startProfilingIfNeed() {
-        if (System.currentTimeMillis() - tracingContext.createTime() > 
executionContext.getTask()
+        if (System.currentTimeMillis() - 
profilingStatus.firstSegmentCreateTime() > executionContext.getTask()
                                                                                
        .getMinDurationThreshold()) {
             this.profilingStartTime = System.currentTimeMillis();
-            
this.tracingContext.profileStatus().updateStatus(ProfileStatus.PROFILING);
+            this.profilingStatus.updateStatus(ProfileStatus.PROFILING, 
tracingContext);
         }
     }
 
@@ -74,7 +74,7 @@ public class ThreadProfiler {
      * Stop profiling status
      */
     public void stopProfiling() {
-        
this.tracingContext.profileStatus().updateStatus(ProfileStatus.STOPPED);
+        this.profilingStatus.updateStatus(ProfileStatus.STOPPED, 
tracingContext);
     }
 
     /**
@@ -133,7 +133,7 @@ public class ThreadProfiler {
      */
     public boolean matches(TracingContext context) {
         // match trace id
-        return Objects.equal(context.getReadablePrimaryTraceId(), 
tracingContext.getReadablePrimaryTraceId());
+        return Objects.equal(context.getSegmentId(), 
tracingContext.getSegmentId());
     }
 
     /**
@@ -149,7 +149,7 @@ public class ThreadProfiler {
         return tracingContext;
     }
 
-    public ProfileStatusReference profilingStatus() {
+    public ProfileStatusContext profilingStatus() {
         return profilingStatus;
     }
 
diff --git 
a/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
 
b/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
index 3773c0988e..505a4924a9 100644
--- 
a/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
+++ 
b/apm-sniffer/apm-test-tools/src/main/java/org/apache/skywalking/apm/agent/core/context/MockContextSnapshot.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.apm.agent.core.context;
 
 import org.apache.skywalking.apm.agent.core.context.ids.NewDistributedTraceId;
+import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
 
 public enum MockContextSnapshot {
     INSTANCE;
@@ -32,7 +33,8 @@ public enum MockContextSnapshot {
             new NewDistributedTraceId(),
             "/for-test-entryOperationName",
             new CorrelationContext(),
-            new ExtensionContext()
+            new ExtensionContext(),
+            ProfileStatusContext.createWithNone()
         );
     }
 
diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config
index a3a335f7b6..fa172b7687 100755
--- a/apm-sniffer/config/agent.config
+++ b/apm-sniffer/config/agent.config
@@ -161,8 +161,10 @@ buffer.channel_size=${SW_BUFFER_CHANNEL_SIZE:5}
 buffer.buffer_size=${SW_BUFFER_BUFFER_SIZE:300}
 # If true, skywalking agent will enable profile when user create a new profile 
task. Otherwise disable profile.
 profile.active=${SW_AGENT_PROFILE_ACTIVE:true}
-# Parallel monitor segment count
+# Parallel monitor endpoint thread count
 profile.max_parallel=${SW_AGENT_PROFILE_MAX_PARALLEL:5}
+# Max monitoring sub-tasks count of one single endpoint access
+profile.max_accept_sub_parallel=${SW_AGENT_PROFILE_MAX_ACCEPT_SUB_PARALLEL:5}
 # Max monitor segment time(minutes), if current segment monitor time out of 
limit, then stop it.
 profile.duration=${SW_AGENT_PROFILE_DURATION:10}
 # Max dump thread stack depth
diff --git a/docs/en/setup/service-agent/java-agent/configurations.md 
b/docs/en/setup/service-agent/java-agent/configurations.md
index 8aafa53908..2df78b1271 100644
--- a/docs/en/setup/service-agent/java-agent/configurations.md
+++ b/docs/en/setup/service-agent/java-agent/configurations.md
@@ -54,6 +54,7 @@ This is the properties list supported in 
`agent/config/agent.config`.
 | `buffer.buffer_size`                                            | The buffer 
size.                                                                           
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
 | `profile.active`                                                | If true, 
skywalking agent will enable profile when user create a new profile task. 
Otherwise disable profile.                                                      
                                                                                
                                                                                
                                                                                
                      [...]
 | `profile.max_parallel`                                          | Parallel 
monitor segment count                                                           
                                                                                
                                                                                
                                                                                
                                                                                
                [...]
+| `profile.max_accept_sub_parallel`                               | Max 
monitoring sub-tasks count of one single endpoint access                        
                                                                                
                                                                                
                                                                                
                                                                                
                     [...]
 | `profile.duration`                                              | Max 
monitor segment time(minutes), if current segment monitor time out of limit, 
then stop it.                                                                   
                                                                                
                                                                                
                                                                                
                        [...]
 | `profile.dump_max_stack_depth`                                  | Max dump 
thread stack depth                                                              
                                                                                
                                                                                
                                                                                
                                                                                
                [...]
 | `profile.snapshot_transport_buffer_size`                        | Snapshot 
transport to backend buffer size                                                
                                                                                
                                                                                
                                                                                
                                                                                
                [...]

Reply via email to