diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 116acf809c6..86d7d56e400 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -320,10 +320,6 @@ class K2Native : CLICompiler() { null } }) - if (memoryModel != MemoryModel.EXPERIMENTAL && arguments.gcAggressive) { - configuration.report(ERROR, "-Xgc-aggressive is only supported for -memory-model experimental") - } - put(GARBAGE_COLLECTOR_AGRESSIVE, arguments.gcAggressive) put(PROPERTY_LAZY_INITIALIZATION, when (arguments.propertyLazyInitialization) { null -> { when (memoryModel) { diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index b5bb59fa685..f756d6c6976 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -330,9 +330,6 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @Argument(value="-Xgc", valueDescription = "", description = "GC to use, 'noop' and 'stms' are currently supported. Works only with -memory-model experimental") var gc: String? = null - @Argument(value="-Xgc-aggressive", description = "Make GC agressive. Works only with -memory-model experimental") - var gcAggressive: Boolean = false - @Argument(value = "-Xir-property-lazy-initialization", valueDescription = "{disable|enable}", description = "Initialize top level properties lazily per file") var propertyLazyInitialization: String? = null diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GCSchedulerType.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GCSchedulerType.kt index 182d5d66a5c..df2befc0287 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GCSchedulerType.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/GCSchedulerType.kt @@ -5,8 +5,10 @@ package org.jetbrains.kotlin.backend.konan +// Must match `GCSchedulerType` in CompilerConstants.hpp enum class GCSchedulerType(val value: Int) { DISABLED(0), WITH_TIMER(1), - ON_SAFE_POINTS(2) -} \ No newline at end of file + ON_SAFE_POINTS(2), + AGGRESSIVE(3), +} diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 7b576957d81..de5d7545c66 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -94,7 +94,6 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration } realGc } - val gcAggressive: Boolean get() = configuration.get(KonanConfigKeys.GARBAGE_COLLECTOR_AGRESSIVE)!! val runtimeAssertsMode: RuntimeAssertsMode get() = configuration.get(BinaryOptions.runtimeAssertionsMode) ?: RuntimeAssertsMode.IGNORE val workerExceptionHandling: WorkerExceptionHandling get() = configuration.get(KonanConfigKeys.WORKER_EXCEPTION_HANDLING)!! val runtimeLogs: String? get() = configuration.get(KonanConfigKeys.RUNTIME_LOGS) @@ -119,7 +118,6 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration val gcSchedulerType: GCSchedulerType by lazy { configuration.get(BinaryOptions.gcSchedulerType) ?: when { !target.supportsThreads() -> GCSchedulerType.ON_SAFE_POINTS - gcAggressive -> GCSchedulerType.ON_SAFE_POINTS else -> GCSchedulerType.WITH_TIMER } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index b08310da73d..29e13b50c4a 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -161,7 +161,6 @@ class KonanConfigKeys { val DESTROY_RUNTIME_MODE: CompilerConfigurationKey = CompilerConfigurationKey.create("when to destroy runtime") val GARBAGE_COLLECTOR: CompilerConfigurationKey = CompilerConfigurationKey.create("gc") - val GARBAGE_COLLECTOR_AGRESSIVE: CompilerConfigurationKey = CompilerConfigurationKey.create("turn on agressive GC mode") val CHECK_LLD_COMPATIBILITY: CompilerConfigurationKey = CompilerConfigurationKey.create("check compatibility with LLD") val PROPERTY_LAZY_INITIALIZATION: CompilerConfigurationKey = CompilerConfigurationKey.create("lazy top level properties initialization") diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index 9a427b97fcd..508b65ac03b 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -2735,7 +2735,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map config_.allocationThresholdBytes) { RuntimeAssert(static_cast(scheduleGC_), "scheduleGC_ cannot be empty"); @@ -75,7 +75,7 @@ public: timeOfLastGcNs_(currentTimeCallbackNs_()), scheduleGC_(std::move(scheduleGC)) {} - void OnSafePoint(gc::GCSchedulerThreadData& threadData) noexcept override { + void UpdateFromThreadData(gc::GCSchedulerThreadData& threadData) noexcept override { size_t allocatedBytes = threadData.allocatedBytes(); if (allocatedBytes > config_.allocationThresholdBytes || currentTimeCallbackNs_() - timeOfLastGcNs_ >= config_.cooldownThresholdNs) { @@ -96,6 +96,24 @@ private: std::function scheduleGC_; }; +class GCSchedulerDataAggressive : public gc::GCSchedulerData { +public: + GCSchedulerDataAggressive(gc::GCSchedulerConfig& config, std::function scheduleGC) noexcept : + scheduleGC_(std::move(scheduleGC)) { + RuntimeLogInfo({kTagGC}, "Initialize GC scheduler config in the aggressive mode"); + // TODO: Make it even more aggressive and run on a subset of backend.native tests. + config.threshold = 1000; + config.allocationThresholdBytes = 10000; + } + + void UpdateFromThreadData(gc::GCSchedulerThreadData& threadData) noexcept override { scheduleGC_(); } + + void OnPerformFullGC() noexcept override {} + void UpdateAliveSetBytes(size_t bytes) noexcept override {} + +private: + std::function scheduleGC_; +}; KStdUniquePtr MakeEmptyGCSchedulerData() noexcept { return ::make_unique(); @@ -111,6 +129,10 @@ KStdUniquePtr MakeGCSchedulerDataWithoutTimer( return ::make_unique(config, std::move(scheduleGC), std::move(currentTimeCallbackNs)); } +KStdUniquePtr MakeGCShedulerDataAggressive(gc::GCSchedulerConfig& config, std::function scheduleGC) noexcept { + return ::make_unique(config, std::move(scheduleGC)); +} + } // namespace KStdUniquePtr kotlin::gc::MakeGCSchedulerData(SchedulerType type, gc::GCSchedulerConfig& config, std::function scheduleGC) noexcept { @@ -121,6 +143,8 @@ KStdUniquePtr kotlin::gc::MakeGCSchedulerData(SchedulerType return MakeGCSchedulerDataWithTimer(config, std::move(scheduleGC)); case SchedulerType::kOnSafepoints: return MakeGCSchedulerDataWithoutTimer(config, std::move(scheduleGC), []() { return konan::getTimeNanos(); }); + case SchedulerType::kAggressive: + return MakeGCShedulerDataAggressive(config, std::move(scheduleGC)); } } diff --git a/kotlin-native/runtime/src/gc/common/cpp/GCScheduler.hpp b/kotlin-native/runtime/src/gc/common/cpp/GCScheduler.hpp index 971d5d21e53..86c8bdf57d8 100644 --- a/kotlin-native/runtime/src/gc/common/cpp/GCScheduler.hpp +++ b/kotlin-native/runtime/src/gc/common/cpp/GCScheduler.hpp @@ -29,17 +29,6 @@ struct GCSchedulerConfig { std::atomic cooldownThresholdNs = 200 * 1000 * 1000; // 200 milliseconds by default. std::atomic autoTune = false; std::atomic regularGcIntervalUs = 200 * 1000; // 200 milliseconds by default. - - GCSchedulerConfig() noexcept { - if (compiler::gcAggressive()) { - // TODO: Make a separate GCSchedulerData for the aggressive mode and move this log there. - RuntimeLogInfo({kTagGC}, "Initialize GC scheduler config in the aggressive mode"); - // TODO: Make it even more aggressive and run on a subset of backend.native tests. - threshold = 1000; - allocationThresholdBytes = 10000; - cooldownThresholdNs = 0; - } - } }; class GCSchedulerThreadData; @@ -49,7 +38,7 @@ public: virtual ~GCSchedulerData() = default; // Called by different mutator threads. - virtual void OnSafePoint(GCSchedulerThreadData& threadData) noexcept = 0; + virtual void UpdateFromThreadData(GCSchedulerThreadData& threadData) noexcept = 0; // Always called by the GC thread. virtual void OnPerformFullGC() noexcept = 0; @@ -63,19 +52,25 @@ public: static constexpr size_t kFunctionPrologueWeight = 1; static constexpr size_t kLoopBodyWeight = 1; - explicit GCSchedulerThreadData(GCSchedulerConfig& config, std::function onSafePoint) noexcept : - config_(config), onSafePoint_(std::move(onSafePoint)) { + explicit GCSchedulerThreadData(GCSchedulerConfig& config, std::function slowPath) noexcept : + config_(config), slowPath_(std::move(slowPath)) { ClearCountersAndUpdateThresholds(); } // Should be called on encountering a safepoint. void OnSafePointRegular(size_t weight) noexcept { - if (compiler::getGCSchedulerType() == compiler::GCSchedulerType::kOnSafepoints) { - safePointsCounter_ += weight; - if (safePointsCounter_ < safePointsCounterThreshold_) { + // TODO: This is a weird design. Consider replacing switch+virtual functions with pimpl+separate compilation. + switch (compiler::getGCSchedulerType()) { + case compiler::GCSchedulerType::kOnSafepoints: + case compiler::GCSchedulerType::kAggressive: + safePointsCounter_ += weight; + if (safePointsCounter_ < safePointsCounterThreshold_) { + return; + } + OnSafePointSlowPath(); + return; + default: return; - } - OnSafePointSlowPath(); } } @@ -97,7 +92,7 @@ public: private: void OnSafePointSlowPath() noexcept { - onSafePoint_(*this); + slowPath_(*this); ClearCountersAndUpdateThresholds(); } @@ -110,7 +105,7 @@ private: } GCSchedulerConfig& config_; - std::function onSafePoint_; + std::function slowPath_; size_t allocatedBytes_ = 0; size_t allocatedBytesThreshold_ = 0; @@ -134,7 +129,7 @@ public: void SetScheduleGC(std::function scheduleGC) noexcept; GCSchedulerThreadData NewThreadData() noexcept { - return GCSchedulerThreadData(config_, [this](auto& threadData) { gcData_->OnSafePoint(threadData); }); + return GCSchedulerThreadData(config_, [this](auto& threadData) { gcData_->UpdateFromThreadData(threadData); }); } private: diff --git a/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp b/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp index a5892df2444..48deebe89c6 100644 --- a/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp +++ b/kotlin-native/runtime/src/main/cpp/CompilerConstants.cpp @@ -12,7 +12,6 @@ using namespace kotlin; // These are defined by overrideRuntimeGlobals in IrToBitcode.kt RUNTIME_WEAK int32_t Kotlin_destroyRuntimeMode = 1; -RUNTIME_WEAK int32_t Kotlin_gcAggressive = 0; RUNTIME_WEAK int32_t Kotlin_gcSchedulerType = 2; RUNTIME_WEAK int32_t Kotlin_workerExceptionHandling = 0; RUNTIME_WEAK int32_t Kotlin_freezingEnabled = 1; @@ -25,10 +24,6 @@ ALWAYS_INLINE compiler::DestroyRuntimeMode compiler::destroyRuntimeMode() noexce return static_cast(Kotlin_destroyRuntimeMode); } -ALWAYS_INLINE bool compiler::gcAggressive() noexcept { - return Kotlin_gcAggressive != 0; -} - ALWAYS_INLINE compiler::WorkerExceptionHandling compiler::workerExceptionHandling() noexcept { return static_cast(Kotlin_workerExceptionHandling); } diff --git a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp index 71c485e9bf3..d64ddb266eb 100644 --- a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp +++ b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp @@ -58,13 +58,12 @@ enum class WorkerExceptionHandling : int32_t { enum class GCSchedulerType { kDisabled = 0, kWithTimer = 1, - kOnSafepoints = 2 + kOnSafepoints = 2, + kAggressive = 3, }; DestroyRuntimeMode destroyRuntimeMode() noexcept; -bool gcAggressive() noexcept; - ALWAYS_INLINE inline bool shouldContainDebugInfo() noexcept { return KonanNeedDebugInfo != 0; }