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

xuanwo pushed a commit to branch xuanwo/java-get-perf
in repository https://gitbox.apache.org/repos/asf/opendal.git

commit dcefe0eb5ceb7a5c1df1e6ea37f762dfc98d4af1
Author: Xuanwo <[email protected]>
AuthorDate: Mon Dec 22 22:47:37 2025 +0800

    Fix build
---
 bindings/java/pom.xml                              |  98 ++++++++++++++
 bindings/java/src/executor.rs                      |   2 +-
 .../java/org/apache/opendal/bench/jmh/Main.java    |  82 ++++++++++++
 .../bench/jmh/OperatorReadJmhBenchmark.java        | 147 +++++++++++++++++++++
 4 files changed, 328 insertions(+), 1 deletion(-)

diff --git a/bindings/java/pom.xml b/bindings/java/pom.xml
index cb8b71be7..10ed56d70 100644
--- a/bindings/java/pom.xml
+++ b/bindings/java/pom.xml
@@ -81,6 +81,9 @@
         <palantir-java-format.version>2.36.0</palantir-java-format.version>
         <spotless.version>2.39.0</spotless.version>
         <maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
+        
<build-helper-maven-plugin.version>3.6.0</build-helper-maven-plugin.version>
+        <maven-shade-plugin.version>3.6.1</maven-shade-plugin.version>
+        <jmh.version>1.37</jmh.version>
     </properties>
 
     <dependencyManagement>
@@ -305,4 +308,99 @@
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>jmh</id>
+            <dependencies>
+                <dependency>
+                    <groupId>org.openjdk.jmh</groupId>
+                    <artifactId>jmh-core</artifactId>
+                    <version>${jmh.version}</version>
+                </dependency>
+                <dependency>
+                    <groupId>org.openjdk.jmh</groupId>
+                    <artifactId>jmh-generator-annprocess</artifactId>
+                    <version>${jmh.version}</version>
+                </dependency>
+            </dependencies>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-jar-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>default-jar</id>
+                                <configuration>
+                                    <excludes combine.self="override"/>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>build-helper-maven-plugin</artifactId>
+                        <version>${build-helper-maven-plugin.version}</version>
+                        <executions>
+                            <execution>
+                                <id>add-jmh-source</id>
+                                <phase>generate-sources</phase>
+                                <goals>
+                                    <goal>add-source</goal>
+                                </goals>
+                                <configuration>
+                                    <sources>
+                                        <source>src/jmh/java</source>
+                                    </sources>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-compiler-plugin</artifactId>
+                        <version>${maven-compiler-plugin.version}</version>
+                        <configuration>
+                            <annotationProcessorPaths>
+                                <path>
+                                    <groupId>org.projectlombok</groupId>
+                                    <artifactId>lombok</artifactId>
+                                    <version>${lombok.version}</version>
+                                </path>
+                                <path>
+                                    <groupId>org.openjdk.jmh</groupId>
+                                    
<artifactId>jmh-generator-annprocess</artifactId>
+                                    <version>${jmh.version}</version>
+                                </path>
+                            </annotationProcessorPaths>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-shade-plugin</artifactId>
+                        <version>${maven-shade-plugin.version}</version>
+                        <executions>
+                            <execution>
+                                <id>shade-jmh</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>shade</goal>
+                                </goals>
+                                <configuration>
+                                    <finalName>benchmarks</finalName>
+                                    
<createDependencyReducedPom>false</createDependencyReducedPom>
+                                    <transformers>
+                                        <transformer 
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                            
<mainClass>org.apache.opendal.bench.jmh.Main</mainClass>
+                                        </transformer>
+                                    </transformers>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/bindings/java/src/executor.rs b/bindings/java/src/executor.rs
index af0dd13f5..caa8263ae 100644
--- a/bindings/java/src/executor.rs
+++ b/bindings/java/src/executor.rs
@@ -129,7 +129,7 @@ pub(crate) fn make_tokio_executor(env: &mut JNIEnv, cores: 
usize) -> Result<Exec
             move || {
                 ENV.with(|cell| {
                     let mut env = vm
-                        .attach_current_thread_permanently()
+                        .attach_current_thread_as_daemon()
                         .expect("attach thread must succeed");
 
                     set_current_thread_name(&mut env)
diff --git a/bindings/java/src/jmh/java/org/apache/opendal/bench/jmh/Main.java 
b/bindings/java/src/jmh/java/org/apache/opendal/bench/jmh/Main.java
new file mode 100644
index 000000000..3169c4bed
--- /dev/null
+++ b/bindings/java/src/jmh/java/org/apache/opendal/bench/jmh/Main.java
@@ -0,0 +1,82 @@
+/*
+ * 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.opendal.bench.jmh;
+
+import java.util.Collection;
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.results.RunResult;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.CommandLineOptions;
+import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.VerboseMode;
+
+public final class Main {
+    private static final double BYTES_PER_MIB = 1024.0 * 1024.0;
+
+    private Main() {}
+
+    public static void main(String[] args) throws Exception {
+        final CommandLineOptions cli = new CommandLineOptions(args);
+
+        final ChainedOptionsBuilder builder = new OptionsBuilder().parent(cli);
+        if (!hasVerbosityArg(args)) {
+            builder.verbosity(VerboseMode.SILENT);
+        }
+
+        final Options opt = builder.build();
+        final Collection<RunResult> results = new Runner(opt).run();
+
+        System.out.println();
+        System.out.println("Benchmark                                       
MiB/s");
+        for (final RunResult rr : results) {
+            final double mibPerSec = toMibPerSec(rr);
+            System.out.printf("%-45s %10.3f%n", rr.getParams().getBenchmark(), 
mibPerSec);
+        }
+    }
+
+    private static double toMibPerSec(RunResult rr) {
+        final BenchmarkParams params = rr.getParams();
+        final String size = params.getParam("sizeBytes");
+        if (size == null) {
+            throw new IllegalStateException("missing sizeBytes parameter for " 
+ params.getBenchmark());
+        }
+        final double mibPerOp = Long.parseLong(size) / BYTES_PER_MIB;
+        final double opsPerSec = rr.getPrimaryResult().getScore();
+        return opsPerSec * mibPerOp;
+    }
+
+    private static boolean hasVerbosityArg(String[] args) {
+        for (int i = 0; i < args.length; i++) {
+            final String a = args[i];
+            if ("-v".equals(a) || "--verbosity".equals(a)) {
+                return true;
+            }
+            if (a.startsWith("-v") && a.length() > 2) {
+                return true;
+            }
+            if (a.startsWith("--verbosity=")) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git 
a/bindings/java/src/jmh/java/org/apache/opendal/bench/jmh/OperatorReadJmhBenchmark.java
 
b/bindings/java/src/jmh/java/org/apache/opendal/bench/jmh/OperatorReadJmhBenchmark.java
new file mode 100644
index 000000000..68125e9b5
--- /dev/null
+++ 
b/bindings/java/src/jmh/java/org/apache/opendal/bench/jmh/OperatorReadJmhBenchmark.java
@@ -0,0 +1,147 @@
+/*
+ * 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.opendal.bench.jmh;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import org.apache.opendal.Operator;
+import org.apache.opendal.OperatorInputStream;
+import org.openjdk.jmh.annotations.AuxCounters;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 1, time = 10, timeUnit = TimeUnit.SECONDS)
+@Fork(1)
+@Threads(1)
+public class OperatorReadJmhBenchmark {
+    private static final double BYTES_PER_MIB = 1024.0 * 1024.0;
+
+    @AuxCounters(AuxCounters.Type.OPERATIONS)
+    @State(Scope.Thread)
+    public static class Counters {
+        public double mibPerSec;
+
+        @Setup(Level.Iteration)
+        public void reset() {
+            mibPerSec = 0.0;
+        }
+    }
+
+    @State(Scope.Thread)
+    public static class BenchmarkState {
+        @Param({"16777216"})
+        public int sizeBytes;
+
+        @Param({"8192"})
+        public int bufferBytes;
+
+        private Operator operator;
+        private String path;
+        private byte[] buf;
+        private OutputStream out;
+
+        @Setup(Level.Trial)
+        public void setup() {
+            final Map<String, String> config = new HashMap<String, String>();
+            this.operator = Operator.of("memory", config);
+            this.path = "bench.bin";
+
+            final byte[] content = new byte[sizeBytes];
+            new Random(0).nextBytes(content);
+            this.operator.write(path, content);
+
+            this.buf = new byte[bufferBytes];
+            this.out = new NullOutputStream();
+        }
+
+        @TearDown(Level.Trial)
+        public void teardown() {
+            if (this.operator != null) {
+                this.operator.close();
+            }
+        }
+    }
+
+    @Benchmark
+    public void readRange(BenchmarkState state, Counters counters, Blackhole 
bh) throws IOException {
+        final byte[] bytes = state.operator.read(state.path, 0, 
state.sizeBytes);
+        if (bytes.length != state.sizeBytes) {
+            throw new IllegalStateException("short read: " + bytes.length + " 
!= " + state.sizeBytes);
+        }
+        state.out.write(bytes);
+        counters.mibPerSec += bytes.length / BYTES_PER_MIB;
+        bh.consume(bytes.length);
+    }
+
+    @Benchmark
+    public void createInputStream(BenchmarkState state, Counters counters, 
Blackhole bh) throws IOException {
+        long total = 0;
+        long acc = 0;
+
+        try (final OperatorInputStream in = 
state.operator.createInputStream(state.path)) {
+            while (true) {
+                final int n = in.read(state.buf);
+                if (n < 0) {
+                    break;
+                }
+                if (n == 0) {
+                    continue;
+                }
+                state.out.write(state.buf, 0, n);
+                total += n;
+                acc ^= ((long) state.buf[0] << 32) ^ (state.buf[n - 1] & 
0xFFL);
+            }
+        }
+
+        if (total != state.sizeBytes) {
+            throw new IllegalStateException("short read: " + total + " != " + 
state.sizeBytes);
+        }
+        counters.mibPerSec += total / BYTES_PER_MIB;
+        bh.consume(acc);
+    }
+
+    private static final class NullOutputStream extends OutputStream {
+        @Override
+        public void write(int b) {}
+
+        @Override
+        public void write(byte[] b, int off, int len) {}
+    }
+}

Reply via email to