Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt to JDK22 #18

Merged
merged 9 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: oracle
java-version: 21
java-version: 22
cache: maven

- name: Check CPU features for Maven tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: oracle
java-version: 21
java-version: 22
cache: maven

- name: Initialize CodeQL
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: oracle
java-version: 21
java-version: 22
cache: maven
- name: Publish to GitHub Packages via Apache Maven
run: mvn -B -DskipTests deploy javadoc:javadoc
Expand Down
32 changes: 6 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ ffmasm
![CodeQL](../../actions/workflows/codeql-analysis.yml/badge.svg)

ffmasm is an assembler for hand-assembling from Java.
It uses Foreign Function & Memory API, so the application can call assembled code via [MethodHandle](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/invoke/MethodHandle.html).
It uses Foreign Function & Memory API, so the application can call assembled code via [MethodHandle](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/invoke/MethodHandle.html).

* Javadoc: https://yasuenag.github.io/ffmasm/
* Maven package: https://github.com/YaSuenag/ffmasm/packages/
* Supported instructions: See builder classes in [com.yasuenag.ffmasm.amd64](https://yasuenag.github.io/ffmasm/com.yasuenag.ffmasm/com/yasuenag/ffmasm/amd64/package-summary.html).

# Requirements

Java 21
Java 22

# Supported platform

Expand Down Expand Up @@ -45,7 +45,7 @@ See [Javadoc](https://yasuenag.github.io/ffmasm/) and [cpumodel](examples/cpumod
## 1. Create `CodeSegment`

`CodeSegment` is a storage for assembled code. In Linux, it would be allocated by `mmap(2)` with executable bit.
It implements [AutoCloseable](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/AutoCloseable.html), so you can use try-with-resources in below:
It implements [AutoCloseable](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/AutoCloseable.html), so you can use try-with-resources in below:

```java
try(var seg = new CodeSegment()){
Expand All @@ -55,7 +55,7 @@ try(var seg = new CodeSegment()){

## 2. Create `MethodHandle` via `AMD64AsmBuilder`

You can assemble the code via `AMD64AsmBuilder`. It would be instanciated via `create()`, and it should be passed both `CodeSegment` and [FunctionDescriptor](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/foreign/FunctionDescriptor.html).
You can assemble the code via `AMD64AsmBuilder`. It would be instanciated via `create()`, and it should be passed both `CodeSegment` and [FunctionDescriptor](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/FunctionDescriptor.html).

In following example, the method is defined as `(I)I` (JNI signature) in `FunctionDescriptor`.
`AMD64AsmBuilder` is builder pattern, so you can add instruction in below. Following example shows method argument (`int`) would be returned straightly.
Expand All @@ -74,10 +74,10 @@ var method = AMD64AsmBuilder.create(seg, desc)
/* mov %rdi, %rax */ .movRM(Register.RDI, Register.RAX, OptionalInt.empty())
/* leave */ .leave()
/* ret */ .ret()
.build(Linker.Option.isTrivial());
.build(Linker.Option.critical(false));
```

NOTE: [Linker.Option.isTrivial()](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/foreign/Linker.Option.html#isTrivial()) is recommended to pass `build()` method due to performance, but it might be cause of some issues in JVM (time to synchronize safepoint, memory corruption, etc). See Javadoc of `isTrivial()`.
NOTE: [Linker.Option.critical()](https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/lang/foreign/Linker.Option.html#critical(boolean)) is recommended to pass `build()` method due to performance, but it might be cause of some issues in JVM (time to synchronize safepoint, memory corruption, etc). See Javadoc of `critical()`.

## 3. Method call

Expand Down Expand Up @@ -126,26 +126,6 @@ try(var seg = new CodeSegment()){
}
```

# Memory pinning

You can pin Java primitive array via `Pinning`. It is same semantics of `GetPrimitiveArrayCritical()` / `ReleasePrimitiveArrayCritical()` in JNI. It expects performance improvement when you refer Java array in ffmasm code. However it might be serious problem (e.g. preventing GC) if you keep pinned memory long time. So you should use it carefully.

Following example shows pin `array` at first, then we modify value via `MemorySegment`.

```java
int[] array = new int[]{1, 2, 3, 4};

var pinnedMem = Pinning.getInstance()
.pin(array)
.reinterpret(ValueLayout.JAVA_INT.byteSize() * array.length);
for(int idx = 0; idx < expected.length; idx++){
pinnedMem.setAtIndex(ValueLayout.JAVA_INT, idx, idx * 2);
}
Pinning.getInstance().unpin(pinnedMem);

// array is {0, 2, 4, 6} at this point
```

# License

The GNU Lesser General Public License, version 3.0
2 changes: 1 addition & 1 deletion benchmarks/funccall/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This benchmark runs RDTSC instruction. JNI function is written in assembly code

# Requirements

* Java 21
* Java 22
* Maven
* GNU Make
* GNU assembler
Expand Down
22 changes: 11 additions & 11 deletions benchmarks/funccall/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<jmh.version>1.35</jmh.version>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<jmh.version>1.37</jmh.version>
</properties>

<dependencies>
Expand All @@ -22,12 +22,6 @@
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.yasuenag</groupId>
<artifactId>ffmasm</artifactId>
Expand All @@ -46,6 +40,13 @@
<arg>-Xlint:all</arg>
</compilerArgs>
<enablePreview>true</enablePreview>
<annotationProcessorPaths>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
Expand Down Expand Up @@ -76,7 +77,6 @@
<argument>-classpath</argument>
<classpath/>
<argument>-Djava.library.path=.</argument>
<argument>--enable-preview</argument>
<argument>--enable-native-access=ALL-UNNAMED</argument>
<argument>com.yasuenag.ffmasm.benchmark.funccall.FuncCallComparison</argument>
</arguments>
Expand All @@ -86,7 +86,7 @@
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.0</version>
<version>3.5.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
@Fork(value = 1, jvmArgsAppend = {"--enable-preview", "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=.", "-Xms4g", "-Xmx4g", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-XX:+AlwaysPreTouch"})
@Fork(value = 1, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED", "-Djava.library.path=.", "-Xms4g", "-Xmx4g", "-XX:+UnlockExperimentalVMOptions", "-XX:+UseEpsilonGC", "-XX:+AlwaysPreTouch"})
@Warmup(iterations = 1, time = 3, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 3, time = 10, timeUnit = TimeUnit.SECONDS)
public class FuncCallComparison{
Expand All @@ -39,7 +39,7 @@ public void setup(){
/* ret */ .ret()
.getMemorySegment();

ffmRDTSC = Linker.nativeLinker().downcallHandle(mem, desc, Linker.Option.isTrivial());
ffmRDTSC = Linker.nativeLinker().downcallHandle(mem, desc, Linker.Option.critical(false));

var register = NativeRegister.create(this.getClass());
register.registerNatives(Map.of(this.getClass().getMethod("rdtscFFMDirect"), mem));
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/vectorapi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This benchmark adds with 256bit packed int. Pure Java and Vector API are expecte

# Requirements

* Java 21
* Java 22
* Maven

# How to build
Expand All @@ -22,5 +22,5 @@ $ mvn package
# Run benchmark

```sh
$ $JAVA_HOME/bin/java -jar target/ffmasm-benchmark-vectorapi-1.0.3.jar
$ $JAVA_HOME/bin/java -jar target/ffmasm-benchmark-vectorapi-1.0.4.jar
```
22 changes: 11 additions & 11 deletions benchmarks/vectorapi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
<groupId>com.yasuenag</groupId>
<artifactId>ffmasm-benchmark-vectorapi</artifactId>
<packaging>jar</packaging>
<version>1.0.3</version>
<version>1.0.4</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<jmh.version>1.35</jmh.version>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<jmh.version>1.37</jmh.version>
</properties>

<dependencies>
Expand All @@ -22,12 +22,6 @@
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.yasuenag</groupId>
<artifactId>ffmasm</artifactId>
Expand All @@ -49,7 +43,13 @@
<arg>--add-exports</arg>
<arg>jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED</arg>
</compilerArgs>
<enablePreview>true</enablePreview>
<annotationProcessorPaths>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
@Fork(value = 1, jvmArgsAppend = {"--enable-preview", "--enable-native-access=ALL-UNNAMED", "--add-modules", "jdk.incubator.vector", "--add-exports", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", "-Xms6g", "-Xmx6g"})
@Fork(value = 1, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED", "--add-modules", "jdk.incubator.vector", "--add-exports", "jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED", "-Xms6g", "-Xmx6g"})
@Warmup(iterations = 1, time = 3, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 3, time = 10, timeUnit = TimeUnit.SECONDS)
public class VectorOpComparison{
Expand All @@ -27,6 +27,8 @@ public class VectorOpComparison{
private MethodHandle ffm;
private MemorySegment srcSeg;
private MemorySegment destSeg;
private MemorySegment pinnedSrcSeg;
private MemorySegment pinnedDestSeg;
private MethodHandle ffmPinned;

private IntVector vectorSrc;
Expand All @@ -47,7 +49,7 @@ public void setup(){
/* vmovdqa %ymm0, (%rdi) */ .vmovdqaRM(Register.YMM0, Register.RDI, OptionalInt.of(0))
/* leave */ .leave()
/* ret */ .ret()
.build(Linker.Option.isTrivial());
.build(Linker.Option.critical(false));

var descPinned = FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.ADDRESS);
ffmPinned = AMD64AsmBuilder.create(AVXAsmBuilder.class, seg, descPinned)
Expand All @@ -59,7 +61,7 @@ public void setup(){
/* vmovdqu %ymm0, (%rdi) */ .vmovdquRM(Register.YMM0, Register.RDI, OptionalInt.of(0))
/* leave */ .leave()
/* ret */ .ret()
.build(Linker.Option.isTrivial());
.build(Linker.Option.critical(true));
}
catch(PlatformException | UnsupportedPlatformException e){
throw new RuntimeException(e);
Expand All @@ -80,49 +82,13 @@ public void paramSetup(){
MemorySegment.copy(randArray, 0, srcSeg, ValueLayout.JAVA_INT, 0, 8);
MemorySegment.copy(result, 0, destSeg, ValueLayout.JAVA_INT, 0, 8);

pinnedSrcSeg = MemorySegment.ofArray(randArray);
pinnedDestSeg = MemorySegment.ofArray(result);

vectorSrc = IntVector.fromArray(IntVector.SPECIES_256, randArray, 0);
vectorDest = IntVector.fromArray(IntVector.SPECIES_256, result, 0);
}

@State(Scope.Benchmark)
public static class PinnedState{

private static final Pinning pinning;

private MemorySegment pinnedSrcSeg;
private MemorySegment pinnedDestSeg;

static{
try{
pinning = Pinning.getInstance();
}
catch(Throwable t){
throw new RuntimeException(t);
}
}

@Setup(Level.Iteration)
public void setup(){
pinnedSrcSeg = pinning.pin(randArray);
pinnedDestSeg = pinning.pin(result);
}

@TearDown(Level.Iteration)
public void tearDownInIterate(){
pinning.unpin(pinnedSrcSeg);
pinning.unpin(pinnedDestSeg);
}

public MemorySegment getPinnedSrcSeg(){
return pinnedSrcSeg;
}

public MemorySegment getPinnedDestSeg(){
return pinnedDestSeg;
}

}

@Benchmark
public int[] invokeJava(){
for(int i = 0; i < 8; i++){
Expand All @@ -143,9 +109,9 @@ public int[] invokeFFM(){
}

@Benchmark
public int[] invokePinnedFFM(PinnedState state){
public int[] invokePinnedFFM(){
try{
ffmPinned.invoke(state.getPinnedDestSeg(), state.getPinnedSrcSeg());
ffmPinned.invoke(pinnedDestSeg, pinnedSrcSeg);
return result;
}
catch(Throwable t){
Expand Down
4 changes: 2 additions & 2 deletions examples/cpumodel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This is an example of ffmasm to obtain CPU model from `CPUID` instruction in AMD

# Requirements

* Java 21
* Java 22
* AMD64 Linux or Windows
* Maven

Expand All @@ -27,7 +27,7 @@ $ mvn clean package
## 3. Run via Maven

```
$ mvn exec:exec
$ mvn exec:java
```

Press enter to exit.
Expand Down
Loading
Loading