Skip to content

Commit d357bde

Browse files
authored
Support keep trace profiling when cross-thread (#479)
1 parent f04866c commit d357bde

File tree

13 files changed

+196
-108
lines changed

13 files changed

+196
-108
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Release Notes.
2020
* Adapt Armeria's plugins to the latest version 1.22.x
2121
* Fix tomcat-10x-plugin and add test case to support tomcat7.x-8.x-9.x.
2222
* Fix thrift plugin generate duplicate traceid when `sendBase` error occurs
23+
* Support keep trace profiling when cross-thread.
2324

2425
#### Documentation
2526
* Update docs of Tracing APIs, reorganize the API docs into six parts.

apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,15 @@ public static class Profile {
241241
public static boolean ACTIVE = true;
242242

243243
/**
244-
* Parallel monitor segment count
244+
* Parallel monitor endpoint thread count
245245
*/
246246
public static int MAX_PARALLEL = 5;
247247

248+
/**
249+
* Max monitoring sub-tasks count of one single endpoint access
250+
*/
251+
public static int MAX_ACCEPT_SUB_PARALLEL = 5;
252+
248253
/**
249254
* Max monitor segment time(minutes), if current segment monitor time out of limit, then stop it.
250255
*/

apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextSnapshot.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import lombok.Getter;
2222
import org.apache.skywalking.apm.agent.core.context.ids.DistributedTraceId;
23+
import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
2324

2425
/**
2526
* The <code>ContextSnapshot</code> is a snapshot for current context. The snapshot carries the info for building
@@ -34,19 +35,22 @@ public class ContextSnapshot {
3435

3536
private CorrelationContext correlationContext;
3637
private ExtensionContext extensionContext;
38+
private ProfileStatusContext profileStatusContext;
3739

3840
ContextSnapshot(String traceSegmentId,
3941
int spanId,
4042
DistributedTraceId primaryTraceId,
4143
String parentEndpoint,
4244
CorrelationContext correlationContext,
43-
ExtensionContext extensionContext) {
45+
ExtensionContext extensionContext,
46+
ProfileStatusContext profileStatusContext) {
4447
this.traceSegmentId = traceSegmentId;
4548
this.spanId = spanId;
4649
this.traceId = primaryTraceId;
4750
this.parentEndpoint = parentEndpoint;
4851
this.correlationContext = correlationContext.clone();
4952
this.extensionContext = extensionContext.clone();
53+
this.profileStatusContext = profileStatusContext.clone();
5054
}
5155

5256
public boolean isFromCurrent() {

apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/IgnoredTracerContext.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.List;
2323
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
2424
import org.apache.skywalking.apm.agent.core.context.trace.NoopSpan;
25+
import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
2526

2627
/**
2728
* The <code>IgnoredTracerContext</code> represent a context should be ignored. So it just maintains the stack with an
@@ -35,13 +36,15 @@ public class IgnoredTracerContext implements AbstractTracerContext {
3536

3637
private final CorrelationContext correlationContext;
3738
private final ExtensionContext extensionContext;
39+
private final ProfileStatusContext profileStatusContext;
3840

3941
private int stackDepth;
4042

4143
public IgnoredTracerContext() {
4244
this.stackDepth = 0;
4345
this.correlationContext = new CorrelationContext();
4446
this.extensionContext = new ExtensionContext();
47+
this.profileStatusContext = ProfileStatusContext.createWithNone();
4548
}
4649

4750
@Override
@@ -56,7 +59,7 @@ public void extract(ContextCarrier carrier) {
5659

5760
@Override
5861
public ContextSnapshot capture() {
59-
return new ContextSnapshot(null, -1, null, null, correlationContext, extensionContext);
62+
return new ContextSnapshot(null, -1, null, null, correlationContext, extensionContext, profileStatusContext);
6063
}
6164

6265
@Override

apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
4242
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
4343
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
44-
import org.apache.skywalking.apm.agent.core.profile.ProfileStatusReference;
44+
import org.apache.skywalking.apm.agent.core.profile.ProfileStatusContext;
4545
import org.apache.skywalking.apm.agent.core.profile.ProfileTaskExecutionService;
4646
import org.apache.skywalking.apm.util.StringUtil;
4747

@@ -106,7 +106,7 @@ public class TracingContext implements AbstractTracerContext {
106106
/**
107107
* profile status
108108
*/
109-
private final ProfileStatusReference profileStatus;
109+
private final ProfileStatusContext profileStatus;
110110
@Getter(AccessLevel.PACKAGE)
111111
private final CorrelationContext correlationContext;
112112
@Getter(AccessLevel.PACKAGE)
@@ -213,7 +213,8 @@ public ContextSnapshot capture() {
213213
getPrimaryTraceId(),
214214
primaryEndpoint.getName(),
215215
this.correlationContext,
216-
this.extensionContext
216+
this.extensionContext,
217+
this.profileStatus
217218
);
218219

219220
return snapshot;
@@ -234,6 +235,9 @@ public void continued(ContextSnapshot snapshot) {
234235
this.correlationContext.continued(snapshot);
235236
this.extensionContext.continued(snapshot);
236237
this.extensionContext.handle(this.activeSpan());
238+
if (this.profileStatus.continued(snapshot)) {
239+
PROFILE_TASK_EXECUTION_SERVICE.continueProfiling(this, this.segment.getTraceSegmentId());
240+
}
237241
}
238242
}
239243

@@ -571,7 +575,7 @@ public long createTime() {
571575
return this.createTime;
572576
}
573577

574-
public ProfileStatusReference profileStatus() {
578+
public ProfileStatusContext profileStatus() {
575579
return this.profileStatus;
576580
}
577581

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package org.apache.skywalking.apm.agent.core.profile;
20+
21+
import org.apache.skywalking.apm.agent.core.conf.Config;
22+
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
23+
import org.apache.skywalking.apm.agent.core.context.TracingContext;
24+
25+
import java.util.concurrent.atomic.AtomicInteger;
26+
27+
/**
28+
* Wrapper {@link ProfileStatus}, make sure {@link org.apache.skywalking.apm.agent.core.context.TracingContext} with {@link ThreadProfiler} have same reference with {@link ProfileStatus},
29+
* And only the profile module could change the status
30+
*/
31+
public class ProfileStatusContext {
32+
33+
private volatile ProfileStatus status;
34+
private volatile long firstSegmentCreateTime;
35+
private volatile AtomicInteger subThreadProfilingCount;
36+
37+
private ProfileStatusContext(ProfileStatus status, long firstSegmentCreateTime, AtomicInteger subThreadProfilingCount) {
38+
this.status = status;
39+
this.firstSegmentCreateTime = firstSegmentCreateTime;
40+
this.subThreadProfilingCount = subThreadProfilingCount;
41+
}
42+
43+
/**
44+
* Create with not watching
45+
*/
46+
public static ProfileStatusContext createWithNone() {
47+
return new ProfileStatusContext(ProfileStatus.NONE, 0, null);
48+
}
49+
50+
/**
51+
* Create with pending to profile
52+
*/
53+
public static ProfileStatusContext createWithPending(long firstSegmentCreateTime) {
54+
return new ProfileStatusContext(ProfileStatus.PENDING, firstSegmentCreateTime, new AtomicInteger(0));
55+
}
56+
57+
public ProfileStatus get() {
58+
return this.status;
59+
}
60+
61+
public long firstSegmentCreateTime() {
62+
return this.firstSegmentCreateTime;
63+
}
64+
65+
/**
66+
* The profile monitoring is watching, wait for some profile conditions.
67+
*/
68+
public boolean isBeingWatched() {
69+
return this.status != ProfileStatus.NONE;
70+
}
71+
72+
public boolean isProfiling() {
73+
return this.status == ProfileStatus.PROFILING;
74+
}
75+
76+
public ProfileStatusContext clone() {
77+
return new ProfileStatusContext(this.status, this.firstSegmentCreateTime, this.subThreadProfilingCount);
78+
}
79+
80+
/**
81+
* Continued profile status context
82+
* @return is needs to keep profile
83+
*/
84+
public boolean continued(ContextSnapshot snapshot) {
85+
this.status = snapshot.getProfileStatusContext().get();
86+
this.firstSegmentCreateTime = snapshot.getProfileStatusContext().firstSegmentCreateTime();
87+
this.subThreadProfilingCount = snapshot.getProfileStatusContext().subThreadProfilingCount;
88+
return this.isBeingWatched() &&
89+
// validate is reach the count of sub-thread
90+
this.subThreadProfilingCount != null &&
91+
this.subThreadProfilingCount.incrementAndGet() <= Config.Profile.MAX_ACCEPT_SUB_PARALLEL;
92+
}
93+
94+
/**
95+
* Update status, only access with profile module
96+
*/
97+
void updateStatus(ProfileStatus status, TracingContext tracingContext) {
98+
this.status = status;
99+
if (this.firstSegmentCreateTime == 0 && tracingContext != null) {
100+
this.firstSegmentCreateTime = tracingContext.createTime();
101+
}
102+
}
103+
104+
void updateStatus(ProfileStatusContext statusContext) {
105+
this.status = statusContext.get();
106+
this.firstSegmentCreateTime = statusContext.firstSegmentCreateTime();
107+
this.subThreadProfilingCount = statusContext.subThreadProfilingCount;
108+
}
109+
110+
}

apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/profile/ProfileStatusReference.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)