Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install System Dependencies
run: apt-get -qq update && apt-get -qq install -y make curl wget
run: apt-get -qq update && apt-get -qq install -y make curl wget libjemalloc2 libjemalloc-dev
- name: Cache JDK
id: cache-jdk
uses: actions/cache@v4
Expand Down Expand Up @@ -86,7 +86,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install System Dependencies
run: apt-get -qq update && apt-get -qq install -y make curl wget
run: apt-get -qq update && apt-get -qq install -y make curl wget libjemalloc2 libjemalloc-dev
- name: Cache JDK
id: cache-jdk
uses: actions/cache@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import Benchmark
import Foundation
import JavaKit
import JavaKitNetwork

@MainActor let benchmarks = {
var jvm: JavaVirtualMachine {
get throws {
try .shared()
}
}
Benchmark("Simple call to Java library") { benchmark in
for _ in benchmark.scaledIterations {
let environment = try jvm.environment()

let urlConnectionClass = try JavaClass<URLConnection>(environment: environment)
blackHole(urlConnectionClass.getDefaultAllowUserInteraction())
}
}
}
69 changes: 69 additions & 0 deletions Benchmarks/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// swift-tools-version: 6.0

import PackageDescription

import class Foundation.FileManager
import class Foundation.ProcessInfo

// Note: the JAVA_HOME environment variable must be set to point to where
// Java is installed, e.g.,
// Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home.
func findJavaHome() -> String {
if let home = ProcessInfo.processInfo.environment["JAVA_HOME"] {
return home
}

// This is a workaround for envs (some IDEs) which have trouble with
// picking up env variables during the build process
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
if let home = try? String(contentsOfFile: path, encoding: .utf8) {
if let lastChar = home.last, lastChar.isNewline {
return String(home.dropLast())
}

return home
}

fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
}
let javaHome = findJavaHome()

let javaIncludePath = "\(javaHome)/include"
#if os(Linux)
let javaPlatformIncludePath = "\(javaIncludePath)/linux"
#elseif os(macOS)
let javaPlatformIncludePath = "\(javaIncludePath)/darwin"
#else
// TODO: Handle windows as well
#error("Currently only macOS and Linux platforms are supported, this may change in the future.")
#endif

let package = Package(
name: "benchmarks",
platforms: [
.macOS("15.03")
],
dependencies: [
.package(path: "../"),
.package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.4.0")),
],
targets: [
.executableTarget(
name: "JavaApiCallBenchmarks",
dependencies: [
.product(name: "JavaRuntime", package: "swift-java"),
.product(name: "JavaKit", package: "swift-java"),
.product(name: "JavaKitNetwork", package: "swift-java"),
.product(name: "Benchmark", package: "package-benchmark"),
],
path: "Benchmarks/JavaApiCallBenchmarks",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool structure is looking good now

swiftSettings: [
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"]),
.swiftLanguageMode(.v5),
],
plugins: [
.plugin(name: "BenchmarkPlugin", package: "package-benchmark")
]
)
]
)
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,12 @@ jextract-generate: jextract-swift generate-JExtract-interface-files
swift run jextract-swift \
--package-name com.example.swift.generated \
--swift-module ExampleSwiftLibrary \
--output-directory ${SAMPLES_DIR}/SwiftKitSampleApp/src/generated/java \
--output-directory ${SAMPLES_DIR}/SwiftKitSampleApp/build/generated/sources/jextract/main \
$(BUILD_DIR)/jextract/ExampleSwiftLibrary/MySwiftLibrary.swiftinterface; \
swift run jextract-swift \
--package-name org.swift.swiftkit.generated \
--swift-module SwiftKitSwift \
--output-directory ${SAMPLES_DIR}/SwiftKitSampleApp/src/generated/java \
--output-directory ${SAMPLES_DIR}/SwiftKitSampleApp/build/generated/sources/jextract/main \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense!

$(BUILD_DIR)/jextract/SwiftKitSwift/SwiftKit.swiftinterface


Expand Down
33 changes: 17 additions & 16 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,18 @@ let package = Package(

// ==== Plugin for building Java code
.plugin(
name: "JavaCompilerPlugin",
targets: [
"JavaCompilerPlugin"
]
name: "JavaCompilerPlugin",
targets: [
"JavaCompilerPlugin"
]
),

// ==== Plugin for wrapping Java classes in Swift
.plugin(
name: "Java2SwiftPlugin",
targets: [
"Java2SwiftPlugin"
]
name: "Java2SwiftPlugin",
targets: [
"Java2SwiftPlugin"
]
),

// ==== jextract-swift (extract Java accessors from Swift interface files)
Expand Down Expand Up @@ -140,6 +140,7 @@ let package = Package(
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: "main"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
.package(url: "https://github.com/apple/swift-collections.git", .upToNextMinor(from: "1.1.0")),
.package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.4.0")),
],
targets: [
.macro(
Expand Down Expand Up @@ -225,16 +226,16 @@ let package = Package(
]
),
.plugin(
name: "JavaCompilerPlugin",
capability: .buildTool()
name: "JavaCompilerPlugin",
capability: .buildTool()
),

.plugin(
name: "Java2SwiftPlugin",
capability: .buildTool(),
dependencies: [
"Java2Swift"
]
name: "Java2SwiftPlugin",
capability: .buildTool(),
dependencies: [
"Java2Swift"
]
),

.target(
Expand Down Expand Up @@ -373,6 +374,6 @@ let package = Package(
.swiftLanguageMode(.v5),
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
]
),
)
]
)
68 changes: 26 additions & 42 deletions Samples/SwiftKitSampleApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.swift.swiftkit.gradle.BuildUtils

plugins {
id("build-logic.java-application-conventions")
id("me.champeau.jmh") version "0.7.2"
}

group = "org.swift.swiftkit"
Expand All @@ -31,43 +32,38 @@ java {
}
}

sourceSets {
generated {
java.srcDir "${buildDir}/generated/src/java/"
}

// Make the 'main' and 'test' source sets depend on the generated sources
main {
compileClasspath += sourceSets.generated.output
runtimeClasspath += sourceSets.generated.output
}
test {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
def jextract = tasks.register("jextract", Exec) {
description = "Extracts Java accessor sources using jextract"

outputs.dir(layout.buildDirectory.dir("generated/sources/jextract/main"))
inputs.dir("$rootDir/Sources/ExampleSwiftLibrary") // monitored library

// any changes in the source generator sources also mean the resulting output might change
inputs.dir("$rootDir/Sources/JExtractSwift")
inputs.dir("$rootDir/Sources/JExtractSwiftTool")

compileClasspath += sourceSets.generated.output
runtimeClasspath += sourceSets.generated.output
workingDir = rootDir
commandLine "make"
args "jextract-generate"
}

sourceSets {
main {
java {
srcDir(jextract)
}
}
}

dependencies {
implementation(project(':SwiftKit'))
generatedImplementation(project(':SwiftKit'))

testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
}

configurations {
generatedImplementation.extendsFrom(mainImplementation)
generatedRuntimeOnly.extendsFrom(mainRuntimeOnly)
}

tasks.named("compileJava").configure {
dependsOn("jextract")
}

tasks.test {
tasks.named('test', Test) {
useJUnitPlatform()
}

Expand All @@ -84,27 +80,15 @@ application {
"--enable-native-access=ALL-UNNAMED",

// Include the library paths where our dylibs are that we want to load and call
"-Djava.library.path=" + BuildUtils.javaLibraryPaths().join(":"),
"-Djava.library.path=" + BuildUtils.javaLibraryPaths(rootDir).join(":"),

// Enable tracing downcalls (to Swift)
"-Djextract.trace.downcalls=true"
]
}

task jextract(type: Exec) {
description = "Extracts Java accessor sources using jextract"
outputs.dir(layout.buildDirectory.dir("generated"))
inputs.dir("$rootDir/Sources/ExampleSwiftLibrary") // monitored library

// any changes in the source generator sources also mean the resulting output might change
inputs.dir("$rootDir/Sources/JExtractSwift")
inputs.dir("$rootDir/Sources/JExtractSwiftTool")

workingDir = rootDir
commandLine "make"
args "jextract-generate"
}

tasks.named("compileGeneratedJava").configure {
dependsOn jextract
jmh {
jvmArgsAppend = [
"-Djava.library.path=" + BuildUtils.javaLibraryPaths(rootDir).join(":"),
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

package org.swift.swiftkit;

import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;

import com.example.swift.generated.MySwiftClass;

public class JavaToSwiftBenchmark {

@State(Scope.Benchmark)
public static class BenchmarkState {
MySwiftClass obj;

@Setup(Level.Trial)
public void beforeALl() {
System.loadLibrary("swiftCore");
System.loadLibrary("ExampleSwiftLibrary");

// Tune down debug statements so they don't fill up stdout
System.setProperty("jextract.trace.downcalls", "false");

obj = new MySwiftClass(1, 2);
}
}

@Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS)
public void simpleSwiftApiCall(BenchmarkState state, Blackhole blackhole) {
blackhole.consume(state.obj.makeRandomIntMethod());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,11 @@

package org.swift.swiftkit;

import com.example.swift.generated.MySwiftClass;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import com.example.swift.generated.MySwiftClass;

public class MySwiftClassTest {

Expand Down
4 changes: 4 additions & 0 deletions Sources/ExampleSwiftLibrary/MySwiftLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ public class MySwiftClass {
p("make int -> 12")
return 12
}

public func makeRandomIntMethod() -> Int {
return Int.random(in: 1..<256)
}
}

@_silgen_name("swift_getTypeByMangledNameInEnvironment")
Expand Down
Loading