Skip to content

Commit 0a87988

Browse files
authored
Optimize observability and debugging experience (#3901)
Debug assembly tracebacks and `Scannable#name` should now take much less time and have a significantly lower allocation rate. One aspect is used in the debug mode or with the `checkpoint()` operator. The `Traces#extractOperatorAssemblyInformationParts` is now greatly optimized. The other aspect is `Scannable#name` which from now on lazily executes the current step name. `Scannable#name` logic may be executed many times, e.g. if a hot code path uses `{Mono,Flux}#log` or Micrometer instrumentation. A new benchmark is added to exercise the traceback extraction from a stacktrace. As the benchmarks were touched, this change also improves two existing benchmarks by utilizing the black hole to which benchmark method return values are implicitly sent.
1 parent 3457c3e commit 0a87988

File tree

5 files changed

+220
-68
lines changed

5 files changed

+220
-68
lines changed

benchmarks/src/main/java/reactor/core/publisher/MonoAllBenchmark.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 VMware Inc. or its affiliates, All Rights Reserved.
2+
* Copyright (c) 2022-2024 VMware Inc. or its affiliates, All Rights Reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,8 +49,8 @@ public static void main(String[] args) throws Exception {
4949

5050
@SuppressWarnings("unused")
5151
@Benchmark
52-
public void measureThroughput() {
53-
Flux.range(0, rangeSize)
52+
public Boolean measureThroughput() {
53+
return Flux.range(0, rangeSize)
5454
.all(i -> i < Integer.MAX_VALUE)
5555
.block();
5656
}

benchmarks/src/main/java/reactor/core/publisher/MonoCallableBenchmark.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 VMware Inc. or its affiliates, All Rights Reserved.
2+
* Copyright (c) 2022-2024 VMware Inc. or its affiliates, All Rights Reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -49,8 +49,8 @@ public static void main(String[] args) throws Exception {
4949

5050
@SuppressWarnings("unused")
5151
@Benchmark
52-
public void measureThroughput() {
53-
Flux.range(0, rangeSize)
52+
public Boolean measureThroughput() {
53+
return Flux.range(0, rangeSize)
5454
.all(i -> i < Integer.MAX_VALUE)
5555
.block();
5656
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2024 VMware Inc. or its affiliates, All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package reactor.core.publisher;
18+
19+
import java.util.concurrent.TimeUnit;
20+
import org.openjdk.jmh.annotations.Benchmark;
21+
import org.openjdk.jmh.annotations.BenchmarkMode;
22+
import org.openjdk.jmh.annotations.Fork;
23+
import org.openjdk.jmh.annotations.Level;
24+
import org.openjdk.jmh.annotations.Measurement;
25+
import org.openjdk.jmh.annotations.Mode;
26+
import org.openjdk.jmh.annotations.OutputTimeUnit;
27+
import org.openjdk.jmh.annotations.Param;
28+
import org.openjdk.jmh.annotations.Scope;
29+
import org.openjdk.jmh.annotations.Setup;
30+
import org.openjdk.jmh.annotations.State;
31+
import org.openjdk.jmh.annotations.Warmup;
32+
33+
@BenchmarkMode({Mode.AverageTime})
34+
@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
35+
@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
36+
@Fork(value = 1)
37+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
38+
@State(Scope.Benchmark)
39+
public class TracesBenchmark {
40+
@Param({"0", "1", "2"})
41+
private int reactorLeadingLines;
42+
43+
@Param({"0", "1", "2"})
44+
private int trailingLines;
45+
46+
private String stackTrace;
47+
48+
@Setup(Level.Iteration)
49+
public void setup() {
50+
stackTrace = createStackTrace(reactorLeadingLines, trailingLines);
51+
}
52+
53+
@SuppressWarnings("unused")
54+
@Benchmark
55+
public String measureThroughput() {
56+
return Traces.extractOperatorAssemblyInformation(stackTrace);
57+
}
58+
59+
private static String createStackTrace(int reactorLeadingLines, int trailingLines) {
60+
StringBuilder sb = new StringBuilder();
61+
for (int i = 0; i < reactorLeadingLines; i++) {
62+
sb.append("\tat reactor.core.publisher.Flux.someOperation(Flux.java:42)\n");
63+
}
64+
sb.append("\tat some.user.package.SomeUserClass.someOperation(SomeUserClass.java:1234)\n");
65+
for (int i = 0; i < trailingLines; i++) {
66+
sb.append("\tat any.package.AnyClass.anyOperation(AnyClass.java:1)\n");
67+
}
68+
return sb.toString();
69+
}
70+
}

reactor-core/src/main/java/reactor/core/Scannable.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ default String name() {
449449
.map(s -> s.scan(Attr.NAME))
450450
.filter(Objects::nonNull)
451451
.findFirst()
452-
.orElse(stepName());
452+
.orElseGet(this::stepName);
453453
}
454454

455455
/**

0 commit comments

Comments
 (0)