Skip to content

Commit 1d3fce9

Browse files
committed
fix: vfs perf and memory leaks
fix: resources located next to bin fix: python vfs for lang resources fix: python imports (don't fail due to unregistered unsafe allocation) chore: add new ffm config chore: cleanup redundant profiles and jars Signed-off-by: Sam Gammon <[email protected]>
1 parent 53faf97 commit 1d3fce9

File tree

45 files changed

+470
-760
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+470
-760
lines changed

packages/cli/build.gradle.kts

+33-9
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ val enableExperimentalLlvmEdge = false
138138
val enableFfm = hostIsLinux && System.getProperty("os.arch") != "aarch64"
139139
val enableEmbeddedResources = false
140140
val enableResourceFilter = false
141-
val enableAuxCache = true
141+
val enableAuxCache = false
142142
val enableAuxCacheTrace = true
143143
val enableJpms = false
144144
val enableConscrypt = false
@@ -147,7 +147,7 @@ val enableEmbeddedJvm = false
147147
val enableEmbeddedBuilder = false
148148
val enableBuildReport = true
149149
val enableHeapReport = false
150-
val enableG1 = false
150+
val enableG1 = true
151151
val enablePreinit = true
152152
val enablePgo = findProperty("elide.pgo") != "false"
153153
val enablePgoSampling = false
@@ -191,7 +191,7 @@ val exclusions = listOfNotNull(
191191
)
192192

193193
// Java Launcher (GraalVM at either EA or LTS)
194-
val edgeJvmTarget = 25
194+
val edgeJvmTarget = 24
195195
val stableJvmTarget = 23
196196

197197
val edgeJvm = JavaVersion.toVersion(edgeJvmTarget)
@@ -230,7 +230,6 @@ val jvmOnlyCompileArgs: List<String> = listOfNotNull(
230230
)
231231

232232
val jvmCompileArgs = listOfNotNull(
233-
"--enable-preview",
234233
"--add-modules=jdk.unsupported",
235234
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED",
236235
// "--add-exports=java.base/jdk.internal.module=ALL-UNNAMED",
@@ -373,7 +372,6 @@ buildConfig {
373372
useKotlinOutput()
374373
buildConfigField("String", "ELIDE_RELEASE_TYPE", if (isRelease) "\"RELEASE\"" else "\"DEV\"")
375374
buildConfigField("String", "ELIDE_TOOL_VERSION", "\"$cliVersion\"")
376-
buildConfigField("String", "GVM_RESOURCES", "\"${gvmResourcesPath}\"")
377375
}
378376

379377
val pklDependencies: Configuration by configurations.creating
@@ -668,7 +666,9 @@ val nativeImageBuildVerbose = properties["nativeImageBuildVerbose"] == "true"
668666
val stagedNativeArgs: List<String> = listOfNotNull(
669667
"-H:+RemoveUnusedSymbols",
670668
"-H:+ParseRuntimeOptions",
671-
"-H:+JNIEnhancedErrorCodes",
669+
"-H:+TrackPrimitiveValues",
670+
"-H:+UsePredicates",
671+
"-H:+AllowUnsafeAllocationOfAllInstantiatedTypes", // fix: oracle/graal#10912
672672
onlyIf(oracleGvm && enableAuxCache, "-H:ReservedAuxiliaryImageBytes=${8 * 1024 * 1024}"),
673673
onlyIf(enableExperimentalLlvmBackend, "-H:CompilerBackend=llvm"),
674674
onlyIf(enableExperimental, "-H:+LayeredBaseImageAnalysis"),
@@ -1057,6 +1057,11 @@ val nativeMonitoring = listOfNotNull(
10571057
onlyIf(enableJmx, "threaddump"),
10581058
).joinToString(",")
10591059

1060+
val ffmConfigPath = layout.projectDirectory
1061+
.file("src/main/resources/META-INF/native-image/dev/elide/elide-cli/ffm.json")
1062+
.asFile
1063+
.path
1064+
10601065
val commonNativeArgs = listOfNotNull(
10611066
// Debugging flags:
10621067
// "--verbose",
@@ -1066,15 +1071,16 @@ val commonNativeArgs = listOfNotNull(
10661071
"-H:+UnlockExperimentalVMOptions",
10671072
onlyIf(enableCustomCompiler && !cCompiler.isNullOrEmpty(), "--native-compiler-path=$cCompiler"),
10681073
onlyIf(isDebug, "-H:+JNIVerboseLookupErrors"),
1074+
onlyIf(isDebug, "-H:+JNIEnhancedErrorCodes"),
10691075
onlyIf(!enableJit, "-J-Dtruffle.TruffleRuntime=com.oracle.truffle.api.impl.DefaultTruffleRuntime"),
10701076
onlyIf(enableFfm, "-H:+ForeignAPISupport"),
1077+
onlyIf(enableFfm, "-H:ForeignConfigurationFiles=$ffmConfigPath"),
10711078
onlyIf(dumpPointsTo, "-H:PrintAnalysisCallTreeType=CSV"),
10721079
onlyIf(dumpPointsTo, "-H:+PrintImageObjectTree"),
10731080
onlyIf(enabledFeatures.isNotEmpty(), "--features=${enabledFeatures.joinToString(",")}"),
10741081
// Common flags:
10751082
"-march=$elideBinaryArch",
10761083
"--no-fallback",
1077-
"--enable-preview",
10781084
"--enable-http",
10791085
"--enable-https",
10801086
"--install-exit-handlers",
@@ -1102,6 +1108,9 @@ val commonNativeArgs = listOfNotNull(
11021108
"-H:+PreserveFramePointer",
11031109
"-H:+ReportExceptionStackTraces",
11041110
"-H:+AddAllCharsets",
1111+
"-H:-IncludeLanguageResources",
1112+
"-H:+CopyLanguageResources",
1113+
"-H:+GenerateEmbeddedResourcesFile",
11051114
"-H:-ReduceImplicitExceptionStackTraceInformation",
11061115
"-H:MaxRuntimeCompileMethods=20000",
11071116
"-H:ExcludeResources=META-INF/native/libumbrella.so",
@@ -1363,6 +1372,7 @@ val jvmDefs = mutableMapOf(
13631372
"elide.kotlin.version" to libs.versions.kotlin.sdk.get(),
13641373
"elide.kotlin.verbose" to "false",
13651374
"elide.nativeTransport.v2" to enableNativeTransportV2.toString(),
1375+
"elide.gvmResources" to gvmResourcesPath,
13661376
"jna.library.path" to nativesPath,
13671377
"jna.boot.library.path" to nativesPath,
13681378
"io.netty.allocator.type" to "adaptive",
@@ -1952,6 +1962,9 @@ tasks {
19521962
jvmDefs.forEach {
19531963
systemProperty(it.key, it.value)
19541964
}
1965+
if (findProperty("elide.initLog") == "true") {
1966+
systemProperty("elide.initLog", "true")
1967+
}
19551968

19561969
systemProperty(
19571970
"micronaut.environments",
@@ -2003,7 +2016,12 @@ tasks {
20032016
listOf(
20042017
"-verbose:class",
20052018
).onlyIf(enableVerboseClassLoading)
2006-
))
2019+
).plus(listOf(
2020+
"-Xms64m",
2021+
"-Xmx4g",
2022+
"-XX:+UnlockExperimentalVMOptions",
2023+
"--enable-native-access=ALL-UNNAMED",
2024+
)))
20072025

20082026
standardInput = System.`in`
20092027
standardOutput = System.out
@@ -2099,7 +2117,13 @@ tasks {
20992117
listOf(
21002118
"-verbose:class",
21012119
).onlyIf(enableVerboseClassLoading)
2102-
))
2120+
).plus(listOf(
2121+
"-Xms64m",
2122+
"-Xmx4g",
2123+
"-XX:+UnlockExperimentalVMOptions",
2124+
"--enable-native-access=ALL-UNNAMED",
2125+
// "-agentpath:/opt/visualvm/visualvm/lib/deployed/jdk16/linux-amd64/libprofilerinterface.so=/opt/visualvm/visualvm/lib,5140",
2126+
)))
21032127

21042128
standardInput = System.`in`
21052129
standardOutput = System.out

packages/cli/detekt-baseline.xml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<ID>MagicNumber:ToolShellCommand.kt$ToolShellCommand$40</ID>
1313
<ID>MagicNumber:ToolShellCommand.kt$ToolShellCommand$80</ID>
1414
<ID>MatchingDeclarationName:SanityTests.kt$SanitySelfTest : SelfTest</ID>
15+
<ID>ReturnCount:Elide.kt$Elide.Companion$@Suppress("SpreadOperator") @JvmStatic internal inline fun exec(args: Array&lt;String>): Int</ID>
1516
<ID>ReturnCount:ExecutionController.kt$ExecutionController$private fun toHost(polyglotException: PolyglotException): Throwable</ID>
1617
<ID>ReturnCount:RuntimeWorkdirManager.kt$RuntimeWorkdirManager$private fun nearestDirectoryWithAnyOfTheseFiles( files: Array&lt;String>, base: File? = null, depth: Int? = null, ): File?</ID>
1718
<ID>ReturnCount:ToolShellCommand.kt$ToolShellCommand$override suspend fun CommandContext.invoke(state: ToolContext&lt;ToolState>): CommandResult</ID>

packages/cli/profiles-25x.zip

-17.8 MB
Binary file not shown.

packages/cli/src/main/kotlin/elide/tool/cli/Elide.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.micronaut.context.ApplicationContextBuilder
2121
import io.micronaut.context.ApplicationContextConfigurer
2222
import io.micronaut.context.BeanContext
2323
import io.micronaut.context.annotation.ContextConfigurer
24+
import io.micronaut.core.annotation.Introspected
2425
import org.graalvm.nativeimage.ImageInfo
2526
import org.graalvm.nativeimage.ProcessProperties
2627
import picocli.CommandLine
@@ -108,6 +109,7 @@ internal val applicationContextBuilder = ApplicationContext
108109
],
109110
)
110111
@Suppress("MemberVisibilityCanBePrivate")
112+
@Introspected
111113
@Context @Singleton class Elide : ToolCommandBase<CommandContext>() {
112114
companion object {
113115
/** Name of the tool. */
@@ -125,6 +127,9 @@ internal val applicationContextBuilder = ApplicationContext
125127
private val bundle = ResourceBundle.getBundle("ElideTool", Locale.US)
126128
private val errHandler = DefaultErrorHandler.acquire()
127129

130+
// Initialization timestamp.
131+
private val initTime by lazy { System.currentTimeMillis() }
132+
128133
// Builder for the CLI entrypoint.
129134
private val cliBuilder get() = CommandLine(Elide::class.java, object: CommandLine.IFactory {
130135
override fun <K : Any?> create(cls: Class<K?>?): K? {
@@ -153,7 +158,9 @@ internal val applicationContextBuilder = ApplicationContext
153158
// Init logging.
154159
@JvmStatic private fun initLog(message: String) {
155160
if (INIT_LOGGING) {
156-
System.err.println("[entry] $message")
161+
val now = System.currentTimeMillis()
162+
val delta = now - initTime
163+
System.err.println("[entry] [${delta}ms] $message")
157164
}
158165
}
159166

@@ -178,6 +185,7 @@ internal val applicationContextBuilder = ApplicationContext
178185
if (tooling) {
179186
dev.elide.cli.bridge.CliNativeBridge.initialize()
180187
}
188+
initLog("Natives ready")
181189
}
182190
}
183191

packages/cli/src/main/kotlin/elide/tool/cli/Statics.kt

+14-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ package elide.tool.cli
1818
import java.io.InputStream
1919
import java.io.OutputStream
2020
import java.io.PrintStream
21-
import java.util.concurrent.atomic.AtomicReference
21+
import java.nio.file.Path
22+
import java.nio.file.Paths
2223
import kotlinx.atomicfu.atomic
2324
import elide.runtime.Logger
2425
import elide.runtime.Logging
@@ -47,10 +48,14 @@ internal object Statics {
4748
}
4849
}
4950

50-
private val initialArgs = atomic<Array<String>>(emptyArray())
51+
@Volatile private var execBinPath: String = ""
52+
@Volatile private var initialArgs = emptyArray<String>()
5153

5254
/** Invocation args. */
53-
internal val args: Array<String> get() = initialArgs.value
55+
internal val args: Array<String> get() = initialArgs
56+
57+
internal val bin: String get() = execBinPath
58+
internal val binPath: Path by lazy { Paths.get(bin).toAbsolutePath() }
5459

5560
// Stream which drops all data.
5661
private val noOpStream by lazy {
@@ -62,21 +67,22 @@ internal object Statics {
6267
val `in`: InputStream get() =
6368
delegatedInStream.value ?: System.`in`
6469

65-
val out: PrintStream get() =
70+
@JvmField var out: PrintStream =
6671
when (disableStreams) {
6772
true -> noOpStream
6873
else -> delegatedOutStream.value ?: System.out
6974
}
7075

71-
val err: PrintStream get() =
76+
@JvmField var err: PrintStream =
7277
when (disableStreams) {
7378
true -> noOpStream
7479
else -> delegatedErrStream.value ?: System.err
7580
}
7681

77-
internal fun mountArgs(args: Array<String>) {
78-
check(initialArgs.value.isEmpty()) { "Args are not initialized yet!" }
79-
initialArgs.value = args
82+
internal fun mountArgs(bin: String, args: Array<String>) {
83+
check(initialArgs.isEmpty()) { "Args are not initialized yet!" }
84+
execBinPath = bin
85+
initialArgs = args
8086
}
8187

8288
internal fun assignStreams(out: PrintStream, err: PrintStream, `in`: InputStream) {

packages/cli/src/main/kotlin/elide/tool/cli/cmd/repl/ToolShellCommand.kt

+33-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent
2222
import ch.qos.logback.core.ConsoleAppender
2323
import io.micronaut.core.annotation.Introspected
2424
import io.micronaut.core.io.IOUtils
25+
import org.graalvm.nativeimage.ImageInfo
2526
import org.graalvm.polyglot.PolyglotException
2627
import org.graalvm.polyglot.Source
2728
import org.graalvm.polyglot.Value
@@ -79,7 +80,6 @@ import elide.runtime.plugins.vfs.VfsListener
7980
import elide.runtime.plugins.vfs.vfs
8081
import elide.tool.cli.*
8182
import elide.tool.cli.GuestLanguage.*
82-
import elide.tool.cli.cfg.ElideCLITool.GVM_RESOURCES
8383
import elide.tool.cli.err.AbstractToolError
8484
import elide.tool.cli.err.ShellError
8585
import elide.tool.cli.options.AccessControlOptions
@@ -287,37 +287,43 @@ private typealias ContextAccessor = () -> PolyglotContext
287287
validate = false,
288288
exclusive = false,
289289
heading = "%nAccess Control:%n",
290-
) internal var accessControl: AccessControlOptions = AccessControlOptions()
290+
)
291+
var accessControl: AccessControlOptions = AccessControlOptions()
291292

292293
/** App environment settings. */
293294
@ArgGroup(
294295
exclusive = false,
295296
heading = "%nEnvironment:%n",
296-
) internal var appEnvironment: EnvironmentConfig = EnvironmentConfig()
297+
)
298+
internal var appEnvironment: EnvironmentConfig = EnvironmentConfig()
297299

298300
/** Chrome inspector settings. */
299301
@ArgGroup(
300302
exclusive = false,
301303
heading = "%nInspector:%n",
302-
) internal var inspector: InspectorConfig = InspectorConfig()
304+
)
305+
internal var inspector: InspectorConfig = InspectorConfig()
303306

304307
/** DAP host settings. */
305308
@ArgGroup(
306309
exclusive = false,
307310
heading = "%nDebugger:%n",
308-
) internal var debugger: DebugConfig = DebugConfig()
311+
)
312+
internal var debugger: DebugConfig = DebugConfig()
309313

310314
/** Language selector. */
311315
@ArgGroup(
312316
exclusive = false,
313317
heading = "%nLanguage Selection:%n",
314-
) internal var language: LanguageSelector = LanguageSelector()
318+
)
319+
internal var language: LanguageSelector = LanguageSelector()
315320

316321
/** Settings specific to JavaScript. */
317322
@ArgGroup(
318323
validate = false,
319324
heading = "%nEngine: JavaScript%n",
320-
) internal var jsSettings: EngineJavaScriptOptions = EngineJavaScriptOptions()
325+
)
326+
internal var jsSettings: EngineJavaScriptOptions = EngineJavaScriptOptions()
321327

322328
/** File to run within the VM. */
323329
@Parameters(
@@ -1359,15 +1365,29 @@ private typealias ContextAccessor = () -> PolyglotContext
13591365
val intrinsics = intrinsicsManager.get().resolver()
13601366

13611367
// resolve entrypoint arguments
1362-
val cmd = ProcessHandle.current().info().command().orElse("elide")
1368+
val cmd = if (ImageInfo.inImageCode()) {
1369+
ProcessHandle.current().info().command().orElse("elide")
1370+
} else {
1371+
"elide"
1372+
}
13631373
val args = Statics.args
13641374

1375+
// configure resource path
1376+
val gvmResources = when (ImageInfo.inImageCode()) {
1377+
true -> Statics.binPath.parent.resolve("resources")
1378+
1379+
// in JVM mode, pull from system properties
1380+
else -> requireNotNull(System.getProperty("elide.gvmResources")) {
1381+
"Failed to resolve GraalVM resources path: please set `elide.gvmResources`"
1382+
}.let { Path(it) }
1383+
}
1384+
13651385
langs.forEach { lang ->
13661386
when (lang) {
13671387
// Primary Engines
13681388
JS -> configure(elide.runtime.plugins.js.JavaScript) {
13691389
logging.debug("Configuring JS VM")
1370-
resourcesPath = GVM_RESOURCES
1390+
resourcesPath = gvmResources
13711391
executable = cmd
13721392
executableList = listOf(cmd).plus(args)
13731393
installIntrinsics(intrinsics, GraalVMGuest.JAVASCRIPT, versionProp)
@@ -1376,18 +1396,18 @@ private typealias ContextAccessor = () -> PolyglotContext
13761396

13771397
WASM -> configure(elide.runtime.plugins.wasm.Wasm) {
13781398
logging.debug("Configuring WASM VM")
1379-
resourcesPath = GVM_RESOURCES
1399+
resourcesPath = gvmResources
13801400
}
13811401

13821402
TYPESCRIPT -> configure(elide.runtime.plugins.typescript.TypeScript) {
13831403
logging.debug("Configuring TypeScript support")
1384-
resourcesPath = GVM_RESOURCES
1404+
resourcesPath = gvmResources
13851405
}
13861406

13871407
// RUBY -> ignoreNotInstalled {
13881408
// install(elide.runtime.plugins.ruby.Ruby) {
13891409
// logging.debug("Configuring Ruby VM")
1390-
// resourcesPath = GVM_RESOURCES
1410+
// resourcesPath = gvmResources
13911411
// executable = cmd
13921412
// executableList = listOf(cmd).plus(args)
13931413
// installIntrinsics(intrinsics, GraalVMGuest.RUBY, versionProp)
@@ -1397,7 +1417,7 @@ private typealias ContextAccessor = () -> PolyglotContext
13971417
PYTHON -> configure(elide.runtime.plugins.python.Python) {
13981418
logging.debug("Configuring Python VM")
13991419
installIntrinsics(intrinsics, GraalVMGuest.PYTHON, versionProp)
1400-
resourcesPath = GVM_RESOURCES
1420+
resourcesPath = gvmResources
14011421
executable = cmd
14021422
executableList = listOf(cmd).plus(args)
14031423
}

packages/cli/src/main/kotlin/elide/tool/cli/main.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import kotlin.system.exitProcess
2929
import elide.tool.cli.Elide.Companion.installStatics
3030

3131
// Whether to enable the experimental V2 entrypoint through Clikt.
32-
private val ENABLE_CLI_ENTRY_V2 = System.getenv("ELIDE_EXPERIMENTAL")?.ifBlank { null } != null
32+
private const val ENABLE_CLI_ENTRY_V2 = false
3333

3434
// Whether to log early init messages.
3535
private const val EARLY_INIT_LOG = false
@@ -147,7 +147,7 @@ fun initializeEntry(args: Array<String>, installStatics: Boolean = true) {
147147
setStaticProperties(binPath)
148148
if (installStatics) {
149149
earlyLog("Installing statics")
150-
Statics.mountArgs(args)
150+
Statics.mountArgs(binPath, args)
151151
installStatics(binPath, args, System.getProperty("user.dir"))
152152
earlyLog("Installing bridge handler for SLF4j")
153153
SLF4JBridgeHandler.install()

0 commit comments

Comments
 (0)