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

feature: Disable unused multithreading to improve performance #3670

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion nativelib/src/main/resources/scala-native/gc/boehm/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <gc/gc.h>
#include "shared/ScalaNativeGC.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "shared/Parsing.h"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ void scalanative_GC_remove_roots(void *addr_low, void *addr_high) {
GC_Roots_RemoveByRange(customRoots, range);
}

#ifdef SCALANATIVE_MULTITHREADING_ENABLED
typedef void *RoutineArgs;
typedef struct {
ThreadStartRoutine fn;
Expand Down Expand Up @@ -183,8 +182,10 @@ void scalanative_GC_set_mutator_thread_state(GC_MutatorThreadState state) {
MutatorThread_switchState(currentMutatorThread, state);
}
void scalanative_GC_yield() {
#ifdef SCALANATIVE_MULTITHREADING_ENABLED
if (atomic_load_explicit(&Synchronizer_stopThreads, memory_order_relaxed))
Synchronizer_yield();
#endif
}
#endif // SCALANATIVE_MULTITHREADING_ENABLED
#endif

#endif // defined(SCALANATIVE_GC_COMMIX)
4 changes: 2 additions & 2 deletions nativelib/src/main/resources/scala-native/gc/immix/ImmixGC.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ size_t scalanative_GC_get_max_heapsize() {
return Parse_Env_Or_Default("GC_MAXIMUM_HEAP_SIZE", Heap_getMemoryLimit());
}

#ifdef SCALANATIVE_MULTITHREADING_ENABLED
typedef void *RoutineArgs;
typedef struct {
ThreadStartRoutine fn;
Expand Down Expand Up @@ -147,10 +146,11 @@ void scalanative_GC_set_mutator_thread_state(GC_MutatorThreadState state) {
}

void scalanative_GC_yield() {
#ifdef SCALANATIVE_MULTITHREADING_ENABLED
if (atomic_load_explicit(&Synchronizer_stopThreads, memory_order_relaxed))
Synchronizer_yield();
#endif
}
#endif // SCALANATIVE_MULTITHREADING_ENABLED

void scalanative_GC_add_roots(void *addr_low, void *addr_high) {
AddressRange range = {addr_low, addr_high};
Expand Down
2 changes: 0 additions & 2 deletions nativelib/src/main/resources/scala-native/gc/none/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ void scalanative_GC_collect() {}

void scalanative_GC_register_weak_reference_handler(void *handler) {}

#ifdef SCALANATIVE_MULTITHREADING_ENABLED
#ifdef _WIN32
HANDLE scalanative_GC_CreateThread(LPSECURITY_ATTRIBUTES threadAttributes,
SIZE_T stackSize, ThreadStartRoutine routine,
Expand All @@ -152,7 +151,6 @@ int scalanative_GC_pthread_create(pthread_t *thread, pthread_attr_t *attr,
return pthread_create(thread, attr, routine, args);
}
#endif
#endif // SCALANATIVE_MULTITHREADING_ENABLED

// ScalaNativeGC interface stubs. None GC does not need STW
void scalanative_GC_set_mutator_thread_state(GC_MutatorThreadState unused){};
Expand Down
52 changes: 49 additions & 3 deletions tools/src/main/scala/scala/scalanative/build/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,18 @@ object Build {
checkWorkdirExists(initialConfig)

// validate Config
val config = Validator.validate(initialConfig)
var config = Validator.validate(initialConfig)
config.logger.debug(config.toString())
def linkNIRForEntries = ScalaNative.link(config, entries(config))

ScalaNative
.link(config, entries(config))
linkNIRForEntries
.flatMap { linkerResult =>
val (updatedConfig, needsToReload) =
postRechabilityAnalysisConfigUpdate(config, linkerResult)
config = updatedConfig
if (needsToReload) linkNIRForEntries
else Future.successful(linkerResult)
}
.flatMap(optimize(config, _))
.flatMap(linkerResult =>
codegen(config, linkerResult)
Expand Down Expand Up @@ -179,6 +186,45 @@ object Build {
LLVM.link(config, analysis, compiled)
}

/** Based on reachability analysis check if config can be tuned for better
* performance
*/
private def postRechabilityAnalysisConfigUpdate(
config: Config,
analysis: ReachabilityAnalysis.Result
): (Config, Boolean) = {
var currentConfig = config
var needsToReload = true

// Each block can modify currentConfig stat,
// modification should be lazy to not reconstruct object when not required
locally { // disable unused mulithreading
val envFlag = "SCALANATIVE_DISABLE_UNUSED_MULTITHREADING"
val suppressDisablingThreads = sys.env.get(envFlag).contains("0")
if (!suppressDisablingThreads && config.compilerConfig.multithreadingSupport) {
// format: off
val jlThread = nir.Global.Top("java.lang.Thread")
val jlThreadStart = jlThread.member(nir.Sig.Method("start", Seq(nir.Type.Unit)))
val jlPlatformContext = nir.Global.Top("java.lang.PlatformThreadContext")
val jlPlatformContextStart = jlPlatformContext.member(nir.Sig.Method("start", Seq(nir.Type.Ref(jlThread), nir.Type.Unit)))
val usesSystemThreads = analysis.infos.contains(jlThreadStart) || analysis.infos.contains(jlPlatformContextStart)
// format: on
if (!usesSystemThreads) {
config.logger.info(
"Detected enabled multithreading, but not found any usage of system threads. " +
"Multihreading will be disabled to improve performance. " +
s"This behavior can be disabled by setting enviornment variable $envFlag=0."
)
currentConfig = currentConfig.withCompilerConfig(
_.withMultithreadingSupport(false)
)
needsToReload = true
}
}
}
currentConfig -> needsToReload
}

/** Links the DWARF debug information found in the object files. */
private def postProcess(config: Config, artifact: Path): Path =
config.logger.time("Postprocessing") {
Expand Down