Skip to content

Commit 84587b4

Browse files
authored
Merge pull request #203 from ktoso/wip-string-benchmarking-and-passing
2 parents a2e8551 + c57b70a commit 84587b4

19 files changed

+428
-56
lines changed

Samples/SwiftKitSampleApp/Package.swift

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ let package = Package(
6060
.target(
6161
name: "MySwiftLibrary",
6262
dependencies: [
63+
.product(name: "JavaKit", package: "swift-java"),
64+
.product(name: "JavaRuntime", package: "swift-java"),
6365
.product(name: "SwiftKitSwift", package: "swift-java"),
6466
],
6567
exclude: [

Samples/SwiftKitSampleApp/Sources/MySwiftLibrary/MySwiftLibrary.swift

+15-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ public func globalTakeInt(i: Int) {
3131
p("i:\(i)")
3232
}
3333

34+
public func globalMakeInt() -> Int {
35+
return 42
36+
}
37+
38+
public func globalWriteString(string: String) -> Int {
39+
return string.count
40+
}
41+
3442
public func globalTakeIntInt(i: Int, j: Int) {
3543
p("i:\(i), j:\(j)")
3644
}
@@ -79,6 +87,11 @@ public class MySwiftClass {
7987
return 12
8088
}
8189

90+
public func writeString(string: String) -> Int {
91+
p("echo -> \(string)")
92+
return string.count
93+
}
94+
8295
public func makeRandomIntMethod() -> Int {
8396
return Int.random(in: 1..<256)
8497
}
@@ -87,8 +100,8 @@ public class MySwiftClass {
87100
// ==== Internal helpers
88101

89102
private func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
90-
print("[swift][\(file):\(line)](\(function)) \(msg)")
91-
fflush(stdout)
103+
// print("[swift][\(file):\(line)](\(function)) \(msg)")
104+
// fflush(stdout)
92105
}
93106

94107
#if os(Linux)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import JavaKit
16+
import JavaRuntime
17+
18+
@JavaClass("com.example.swift.HelloJava2Swift")
19+
open class HelloJava2Swift: JavaObject {
20+
}
21+
22+
extension JavaClass<HelloJava2Swift> {
23+
}
24+
25+
/// Describes the Java `native` methods for ``HelloJava2Swift``.
26+
///
27+
/// To implement all of the `native` methods for HelloSwift in Swift,
28+
/// extend HelloSwift to conform to this protocol and mark each
29+
/// implementation of the protocol requirement with `@JavaMethod`.
30+
protocol HelloJava2SwiftNativeMethods {
31+
func jniWriteString(_ message: String) -> Int32
32+
func jniGetInt() -> Int32
33+
}
34+
35+
@JavaImplementation("com.example.swift.HelloJava2Swift")
36+
extension HelloJava2Swift: HelloJava2SwiftNativeMethods {
37+
@JavaMethod
38+
func jniWriteString(_ message: String) -> Int32 {
39+
return Int32(message.count)
40+
}
41+
42+
@JavaMethod
43+
func jniGetInt() -> Int32 {
44+
return 12
45+
}
46+
}

Samples/SwiftKitSampleApp/build.gradle

+11
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,21 @@ application {
145145
]
146146
}
147147

148+
String jmhIncludes = findProperty("jmhIncludes")
149+
148150
jmh {
151+
if (jmhIncludes != null) {
152+
includes = [jmhIncludes]
153+
}
154+
149155
jvmArgsAppend = [
156+
"--enable-native-access=ALL-UNNAMED",
157+
150158
"-Djava.library.path=" +
151159
(BuildUtils.javaLibraryPaths(rootDir) +
152160
BuildUtils.javaLibraryPaths(project.projectDir)).join(":"),
161+
162+
// Enable tracing downcalls (to Swift)
163+
"-Djextract.trace.downcalls=false"
153164
]
154165
}

Samples/SwiftKitSampleApp/src/jmh/java/org/swift/swiftkit/JavaToSwiftBenchmark.java

+32-22
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,51 @@
1414

1515
package org.swift.swiftkit;
1616

17-
import java.util.concurrent.TimeUnit;
18-
19-
import org.openjdk.jmh.annotations.Benchmark;
20-
import org.openjdk.jmh.annotations.BenchmarkMode;
21-
import org.openjdk.jmh.annotations.Level;
22-
import org.openjdk.jmh.annotations.Mode;
23-
import org.openjdk.jmh.annotations.OutputTimeUnit;
24-
import org.openjdk.jmh.annotations.Scope;
25-
import org.openjdk.jmh.annotations.Setup;
26-
import org.openjdk.jmh.annotations.State;
27-
import org.openjdk.jmh.infra.Blackhole;
17+
import com.example.swift.HelloJava2Swift;
18+
import com.example.swift.MySwiftLibrary;
19+
import org.openjdk.jmh.annotations.*;
2820

2921
import com.example.swift.MySwiftClass;
3022

31-
@SuppressWarnings("unused")
23+
import java.util.concurrent.TimeUnit;
24+
25+
@BenchmarkMode(Mode.AverageTime)
26+
@Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
27+
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
28+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
29+
@Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" })
3230
public class JavaToSwiftBenchmark {
3331

3432
@State(Scope.Benchmark)
3533
public static class BenchmarkState {
34+
ClosableSwiftArena arena;
3635
MySwiftClass obj;
3736

3837
@Setup(Level.Trial)
39-
public void beforeALl() {
40-
System.loadLibrary("swiftCore");
41-
System.loadLibrary("ExampleSwiftLibrary");
42-
43-
// Tune down debug statements so they don't fill up stdout
44-
System.setProperty("jextract.trace.downcalls", "false");
38+
public void beforeAll() {
39+
arena = SwiftArena.ofConfined();
40+
obj = new MySwiftClass(arena, 1, 2);
41+
}
4542

46-
obj = new MySwiftClass(1, 2);
43+
@TearDown(Level.Trial)
44+
public void afterAll() {
45+
arena.close();
4746
}
4847
}
4948

50-
@Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
51-
public void simpleSwiftApiCall(BenchmarkState state, Blackhole blackhole) {
52-
blackhole.consume(state.obj.makeRandomIntMethod());
49+
@Benchmark
50+
public long jextract_getInt_ffm(BenchmarkState state) {
51+
return MySwiftLibrary.globalMakeInt();
5352
}
53+
54+
@Benchmark
55+
public long getInt_global_jni(BenchmarkState state) {
56+
return HelloJava2Swift.jniGetInt();
57+
}
58+
59+
@Benchmark
60+
public long getInt_member_ffi(BenchmarkState state) {
61+
return state.obj.makeIntMethod();
62+
}
63+
5464
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
package org.swift.swiftkit;
16+
17+
import com.example.swift.HelloJava2Swift;
18+
import com.example.swift.MySwiftClass;
19+
import com.example.swift.MySwiftLibrary;
20+
import org.openjdk.jmh.annotations.*;
21+
22+
import java.lang.foreign.Arena;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.concurrent.TimeUnit;
25+
26+
@BenchmarkMode(Mode.AverageTime)
27+
@Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
28+
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
29+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
30+
@State(Scope.Thread)
31+
@Fork(value = 2, jvmArgsAppend = {"--enable-native-access=ALL-UNNAMED"})
32+
public class StringPassingBenchmark {
33+
34+
@Param({
35+
"5",
36+
"10",
37+
"100",
38+
"200"
39+
})
40+
public int stringLen;
41+
public String string;
42+
43+
ClosableSwiftArena arena;
44+
MySwiftClass obj;
45+
46+
@Setup(Level.Trial)
47+
public void beforeAll() {
48+
arena = SwiftArena.ofConfined();
49+
obj = new MySwiftClass(arena, 1, 2);
50+
string = makeString(stringLen);
51+
}
52+
53+
@TearDown(Level.Trial)
54+
public void afterAll() {
55+
arena.close();
56+
}
57+
58+
@Benchmark
59+
public long writeString_global_fmm() {
60+
return MySwiftLibrary.globalWriteString(string);
61+
}
62+
63+
@Benchmark
64+
public long writeString_global_jni() {
65+
return HelloJava2Swift.jniWriteString(string);
66+
}
67+
68+
@Benchmark
69+
public long writeString_baseline() {
70+
return string.length();
71+
}
72+
73+
static String makeString(int size) {
74+
var text =
75+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut in augue ullamcorper, mattis lacus tincidunt, " +
76+
"accumsan massa. Morbi gravida purus ut porttitor iaculis. Vestibulum lacinia, mi in tincidunt hendrerit," +
77+
"lectus est placerat magna, vitae vestibulum nulla ligula at massa. Pellentesque nibh quam, pulvinar eu " +
78+
"nunc congue, molestie molestie augue. Nam convallis consectetur velit, at dictum risus ullamcorper iaculis. " +
79+
"Vestibulum lacinia nisi in elit consectetur vulputate. Praesent id odio tristique, tincidunt arcu et, convallis velit. " +
80+
"Sed vitae pulvinar arcu. Curabitur euismod mattis dui in suscipit. Morbi aliquet facilisis vulputate. Phasellus " +
81+
"non lectus dapibus, semper magna eu, aliquet magna. Suspendisse vel enim at augue luctus gravida. Suspendisse " +
82+
"venenatis justo non accumsan sollicitudin. Suspendisse vitae ornare odio, id blandit nibh. Nulla facilisi. " +
83+
"Nulla nulla orci, finibus nec luctus et, faucibus et ligula.";
84+
return text.substring(0, size);
85+
}
86+
}

Samples/SwiftKitSampleApp/src/main/java/com/example/swift/HelloJava2Swift.java

+4
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,8 @@ static void examples() {
5656

5757
System.out.println("DONE.");
5858
}
59+
60+
public static native long jniWriteString(String str);
61+
public static native long jniGetInt();
62+
5963
}

Samples/SwiftKitSampleApp/src/test/java/com/example/swift/MySwiftLibraryTest.java

+21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.example.swift;
1616

17+
import com.example.swift.MySwiftLibrary;
1718
import org.junit.jupiter.api.BeforeAll;
1819
import org.junit.jupiter.api.Disabled;
1920
import org.junit.jupiter.api.Test;
@@ -27,6 +28,10 @@
2728

2829
public class MySwiftLibraryTest {
2930

31+
static {
32+
System.loadLibrary(MySwiftLibrary.LIB_NAME);
33+
}
34+
3035
@Test
3136
void call_helloWorld() {
3237
MySwiftLibrary.helloWorld();
@@ -41,6 +46,22 @@ void call_globalTakeInt() {
4146
assertNotNull(MySwiftLibrary.globalTakeInt$address());
4247
}
4348

49+
@Test
50+
void call_writeString_jextract() {
51+
var string = "Hello Swift!";
52+
long reply = MySwiftLibrary.globalWriteString(string);
53+
54+
assertEquals(string.length(), reply);
55+
}
56+
57+
@Test
58+
void call_writeString_jni() {
59+
var string = "Hello Swift!";
60+
long reply = HelloJava2Swift.jniWriteString(string);
61+
62+
assertEquals(string.length(), reply);
63+
}
64+
4465
@Test
4566
@Disabled("Upcalls not yet implemented in new scheme")
4667
@SuppressWarnings({"Convert2Lambda", "Convert2MethodRef"})

Sources/JExtractSwift/ImportedDecls.swift

+12
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ public struct ImportedParam {
9090
var effectiveName: String? {
9191
firstName ?? secondName
9292
}
93+
94+
var effectiveValueName: String {
95+
secondName ?? firstName ?? "_"
96+
}
9397

9498
// The Swift type as-is from the swift interface
9599
var swiftType: String {
@@ -113,6 +117,14 @@ extension ImportedParam {
113117
}
114118
}
115119

120+
public enum ParameterVariant {
121+
/// Used when declaring the "Swift thunks" we call through into Swift.
122+
///
123+
/// Some types need to be represented as raw pointers and recovered into
124+
/// Swift types inside the thunks when we do this.
125+
case cDeclThunk
126+
}
127+
116128
// TODO: this is used in different contexts and needs a cleanup
117129
// Perhaps this is "which parameter passing style"?
118130
public enum SelfParameterVariant {

Sources/JExtractSwift/JavaTypes.swift

+5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ extension JavaType {
2020
.class(package: "java.lang.foreign", name: "MemorySegment")
2121
}
2222

23+
/// The description of the type java.lang.String.
24+
static var javaLangString: JavaType {
25+
.class(package: "java.lang", name: "String")
26+
}
27+
2328
/// The description of the type java.lang.Runnable.
2429
static var javaLangRunnable: JavaType {
2530
.class(package: "java.lang", name: "Runnable")

0 commit comments

Comments
 (0)