22
22
import java .util .List ;
23
23
import java .util .concurrent .CountDownLatch ;
24
24
import java .util .concurrent .CyclicBarrier ;
25
- import java .util .concurrent .atomic .AtomicLong ;
26
25
27
26
import static org .junit .jupiter .api .Assertions .*;
28
27
34
33
* - Multiple threads calling put() operations (shared lock)
35
34
* - JFR dump operations calling processTraces() (exclusive lock)
36
35
*/
37
- public class ContendedStorageTest extends AbstractProfilerTest {
36
+ public class ContendedCallTraceStorageTest extends AbstractProfilerTest {
38
37
39
38
@ Override
40
39
protected String getProfilerCommand () {
@@ -57,12 +56,8 @@ public void shouldShowImprovedContentionWithRetries() throws Exception {
57
56
58
57
for (ContentionResult currentResult : currentResults ) {
59
58
// For this test, we verify that contention measurement works
60
- assertTrue (currentResult .droppedSamples == 0 , "Should measure dropped samples" );
61
59
assertTrue (currentResult .totalAttempts > 0 , "Should measure total attempts" );
62
-
63
- System .out .printf ("Contention measurement successful: %d/%d samples dropped (%.2f%%)%n" ,
64
- currentResult .droppedSamples , currentResult .totalAttempts ,
65
- (double ) currentResult .droppedSamples / currentResult .totalAttempts * 100 );
60
+ assertTrue (currentResult .droppedSamples / (double ) currentResult .totalAttempts < 0.1f , "Should not drop more than 10% of samples" );
66
61
}
67
62
68
63
// The key insight: this test framework can be used to validate
@@ -145,19 +140,19 @@ private List<ContentionResult> analyzeContentionFromJFR(List<Path> recordings) t
145
140
IItemCollection cpuEvents = events .apply (ItemFilters .type ("datadog.ExecutionSample" ));
146
141
IItemCollection allocationEvents = events .apply (ItemFilters .type ("jdk.ObjectAllocationInNewTLAB" ));
147
142
148
- // Count events with and without stack traces
149
- long cpuWithStack = countEventsWithStackTrace (cpuEvents );
150
- long cpuWithoutStack = countEventsWithoutStackTrace (cpuEvents );
151
- long allocWithStack = countEventsWithStackTrace (allocationEvents );
152
- long allocWithoutStack = countEventsWithoutStackTrace (allocationEvents );
143
+ // Count events with regular stack traces vs dropped traces
144
+ long cpuWithRegularStack = countEventsWithRegularStackTrace (cpuEvents );
145
+ long cpuWithDroppedStack = countEventsWithDroppedStackTrace (cpuEvents );
146
+ long allocWithRegularStack = countEventsWithRegularStackTrace (allocationEvents );
147
+ long allocWithDroppedStack = countEventsWithDroppedStackTrace (allocationEvents );
153
148
154
- // Events without stack traces indicate contention - CallTraceStorage::put() returned 0
155
- long contentionDrops = cpuWithoutStack + allocWithoutStack ;
156
- long totalEvents = cpuWithStack + cpuWithoutStack + allocWithStack + allocWithoutStack ;
149
+ // Events with dropped stack traces indicate contention - CallTraceStorage::put() returned DROPPED_TRACE_ID
150
+ long contentionDrops = cpuWithDroppedStack + allocWithDroppedStack ;
151
+ long totalEvents = cpuWithRegularStack + cpuWithDroppedStack + allocWithRegularStack + allocWithDroppedStack ;
157
152
158
153
System .out .printf ("JFR Contention Analysis:%n" );
159
- System .out .printf (" CPU: %d with stack, %d without stack%n" , cpuWithStack , cpuWithoutStack );
160
- System .out .printf (" Alloc: %d with stack, %d without stack%n" , allocWithStack , allocWithoutStack );
154
+ System .out .printf (" CPU: %d with regular stack, %d with dropped stack%n" , cpuWithRegularStack , cpuWithDroppedStack );
155
+ System .out .printf (" Alloc: %d with regular stack, %d with dropped stack%n" , allocWithRegularStack , allocWithDroppedStack );
161
156
System .out .printf (" Contention drops: %d/%d (%.2f%%)%n" ,
162
157
contentionDrops , totalEvents ,
163
158
totalEvents > 0 ? (double ) contentionDrops / totalEvents * 100 : 0 );
@@ -167,30 +162,40 @@ private List<ContentionResult> analyzeContentionFromJFR(List<Path> recordings) t
167
162
return results ;
168
163
}
169
164
170
- private long countEventsWithStackTrace (IItemCollection events ) {
165
+ private long countEventsWithRegularStackTrace (IItemCollection events ) {
171
166
if (!events .hasItems ()) return 0 ;
172
167
173
168
long count = 0 ;
174
169
for (IItemIterable iterable : events ) {
175
170
for (IItem item : iterable ) {
176
171
IMCStackTrace stackTrace = STACK_TRACE .getAccessor (iterable .getType ()).getMember (item );
177
172
if (stackTrace != null && !stackTrace .getFrames ().isEmpty ()) {
178
- count ++;
173
+ // Check if this is NOT the dropped trace (contains method with "dropped")
174
+ String topMethodName = stackTrace .getFrames ().get (0 ).getMethod ().getMethodName ();
175
+ if (!topMethodName .contains ("dropped" )) {
176
+ count ++;
177
+ }
179
178
}
180
179
}
181
180
}
182
181
return count ;
183
182
}
184
183
185
- private long countEventsWithoutStackTrace (IItemCollection events ) {
184
+ private long countEventsWithDroppedStackTrace (IItemCollection events ) {
186
185
if (!events .hasItems ()) return 0 ;
187
186
188
187
long count = 0 ;
189
188
for (IItemIterable iterable : events ) {
190
189
for (IItem item : iterable ) {
191
190
IMCStackTrace stackTrace = STACK_TRACE .getAccessor (iterable .getType ()).getMember (item );
192
- if (stackTrace == null || stackTrace .getFrames ().isEmpty ()) {
193
- count ++;
191
+ if (stackTrace != null && !stackTrace .getFrames ().isEmpty ()) {
192
+ // Check if this is the special dropped trace (single frame with "dropped" method)
193
+ if (stackTrace .getFrames ().size () == 1 ) {
194
+ String methodName = stackTrace .getFrames ().get (0 ).getMethod ().getMethodName ();
195
+ if (methodName .contains ("dropped" )) {
196
+ count ++;
197
+ }
198
+ }
194
199
}
195
200
}
196
201
}
0 commit comments