diff --git a/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/CodeProfilingPlugin.java b/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/CodeProfilingPlugin.java index 8c428d167fe2..33b25b289ea1 100644 --- a/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/CodeProfilingPlugin.java +++ b/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/CodeProfilingPlugin.java @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.util.List; +import java.util.Locale; import org.apache.lucene.gradle.plugins.LuceneGradlePlugin; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; @@ -189,7 +190,7 @@ public void apply(Project project) { task.jvmArgs( List.of( "-XX:StartFlightRecording=dumponexit=true,maxsize=250M,settings=" - + gradlePluginResource(project, "testing/profiling.jfc"), + + gradlePluginResource(project, profilingSettingsPath()), "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints")); task.dependsOn(cleanPreviousProfiles); @@ -254,4 +255,15 @@ private record ProfilingOptions( Provider countOption, Provider lineNumbersOption, Provider frametypesOption) {} + + /** + * Java 25+ JEP 509 ({@code jdk.CPUTimeSample}) is currently implemented only on Linux in the JDK. + * When the Gradle host is Linux, use {@code testing/profiling.cputime.jfc} (CPU-time sampling + * only). Otherwise use {@code testing/profiling.jfc} (legacy wall-clock execution sampling). Host + * selection may broaden if CPU-time sampling is supported on other OS releases later. + */ + private static String profilingSettingsPath() { + String os = System.getProperty("os.name", "").toLowerCase(Locale.ROOT); + return os.contains("linux") ? "testing/profiling.cputime.jfc" : "testing/profiling.jfc"; + } } diff --git a/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/ProfileResults.java b/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/ProfileResults.java index 802cef5f6d55..0acdb48df636 100644 --- a/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/ProfileResults.java +++ b/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/plugins/java/ProfileResults.java @@ -105,8 +105,16 @@ static boolean isInteresting(String mode, RecordedEvent event) { String name = event.getEventType().getName(); switch (mode) { case "cpu": - return (name.equals("jdk.ExecutionSample") || name.equals("jdk.NativeMethodSample")) - && !isGradlePollThread(event.getThread("sampledThread")); + // jdk.CPUTimeSample: JEP 509 (e.g. gradle/testing/profiling.cputime.jfc). Legacy samples: + // jdk.ExecutionSample / jdk.NativeMethodSample (e.g. profiling.jfc). Stock Lucene configs + // enable one family; filter gradle poll thread for legacy samples only. + if (name.equals("jdk.CPUTimeSample")) { + return true; + } + if (name.equals("jdk.ExecutionSample") || name.equals("jdk.NativeMethodSample")) { + return !isGradlePollThread(event.getThread("sampledThread")); + } + return false; case "heap": return (name.equals("jdk.ObjectAllocationInNewTLAB") || name.equals("jdk.ObjectAllocationOutsideTLAB")) @@ -132,6 +140,8 @@ static long getValue(RecordedEvent event) { return 1L; case "jdk.NativeMethodSample": return 1L; + case "jdk.CPUTimeSample": + return 1L; default: throw new UnsupportedOperationException(event.toString()); } @@ -173,6 +183,7 @@ public static void printReport( if (count < 1) { throw new IllegalArgumentException("tests.profile.count must be positive"); } + Map> histogram = new HashMap<>(); int totalEvents = 0; long sumValues = 0; diff --git a/gradle/testing/profiling.cputime.jfc b/gradle/testing/profiling.cputime.jfc new file mode 100644 index 000000000000..a632754b35fa --- /dev/null +++ b/gradle/testing/profiling.cputime.jfc @@ -0,0 +1,39 @@ + + + + + + true + 1 ms + + + + true + true + + + + true + true + + diff --git a/gradle/testing/profiling.jfc b/gradle/testing/profiling.jfc index d2b95b26d60f..84f0c2db3e32 100644 --- a/gradle/testing/profiling.jfc +++ b/gradle/testing/profiling.jfc @@ -16,7 +16,9 @@ limitations under the License. --> diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 134d529a0385..91e0a1c1609b 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -185,6 +185,11 @@ Changes in Runtime Behavior Build --------------------- +* GITHUB#15926: Use the Java 25+ (JEP 509) CPU-time sampling profiler when available (currently + only on Linux), and fall back to legacy wall-clock execution sampling elsewhere. ProfileResults + recognizes jdk.CPUTimeSample; CodeProfilingPlugin picks gradle/testing/profiling.cputime.jfc or + profiling.jfc by host OS. (Prithvi S) + * GITHUB#15327: New low-level build options to detect abuse of LuceneTestCase.random(): tests.random.maxacquires and tests.random.maxcalls (Robert Muir, Dawid Weiss)