[K/N] Implement Platform.availableProcessors
^KT-48179
This commit is contained in:
@@ -4114,11 +4114,7 @@ createInterop("sysstat") {
|
||||
}
|
||||
|
||||
createInterop("cstdlib") {
|
||||
def f = File.createTempFile("cstdlib.empty", ".def")
|
||||
it.packageName 'cstdlib'
|
||||
// it.headers 'stdlib.h'
|
||||
f.write("headers = stdlib.h")
|
||||
it.defFile f
|
||||
it.defFile 'interop/basics/cstdlib.def'
|
||||
}
|
||||
|
||||
createInterop("cstdio") {
|
||||
@@ -4424,6 +4420,15 @@ standaloneTest("interop_objc_allocException") {
|
||||
UtilsKt.dependsOnPlatformLibs(it)
|
||||
}
|
||||
|
||||
interopTest("interop_available_processors") {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
source = 'interop/basics/available_processors.kt'
|
||||
interop = 'cstdlib'
|
||||
outputChecker = {
|
||||
s -> Integer.parseInt(s.trim()) == Runtime.getRuntime().availableProcessors()
|
||||
}
|
||||
}
|
||||
|
||||
interopTest("interop0") {
|
||||
disabled = (project.testTarget == 'wasm32') || // No interop for wasm yet.
|
||||
(project.testTarget == 'linux_mips32') || // st_uid of '/' is not equal to 0 when using qemu
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
import kotlin.native.*
|
||||
import kotlin.test.*
|
||||
import cstdlib.*
|
||||
import kotlinx.cinterop.*
|
||||
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun main() {
|
||||
val x = Platform.getAvailableProcessors()
|
||||
println(x)
|
||||
assertTrue(x > 0)
|
||||
setenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS", "12345", 1)
|
||||
assertEquals(Platform.getAvailableProcessors(), 12345)
|
||||
setenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS", Long.MAX_VALUE.toString(), 1)
|
||||
assertFailsWith<IllegalStateException> { Platform.getAvailableProcessors() }
|
||||
setenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS", "-1", 1)
|
||||
assertFailsWith<IllegalStateException> { Platform.getAvailableProcessors() }
|
||||
setenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS", "0", 1)
|
||||
assertFailsWith<IllegalStateException> { Platform.getAvailableProcessors() }
|
||||
// windows doesn't support empty env variables
|
||||
if (Platform.osFamily != OsFamily.WINDOWS) {
|
||||
setenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS", "", 1)
|
||||
assertFailsWith<IllegalStateException> { Platform.getAvailableProcessors() }
|
||||
}
|
||||
setenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS", "123aaaa", 1)
|
||||
assertFailsWith<IllegalStateException> { Platform.getAvailableProcessors() }
|
||||
unsetenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS")
|
||||
assertEquals(Platform.getAvailableProcessors(), x)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
headers = stdlib.h
|
||||
compilerOpts.mingw = -D ADD_WINDOWS_ENV_FUNCTIONS
|
||||
|
||||
---
|
||||
|
||||
#ifdef ADD_WINDOWS_ENV_FUNCTIONS
|
||||
static inline int setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
int errcode = 0;
|
||||
if (!overwrite) {
|
||||
size_t envsize = 0;
|
||||
errcode = getenv_s(&envsize, NULL, 0, name);
|
||||
if(errcode || envsize) return errcode;
|
||||
}
|
||||
return _putenv_s(name, value);
|
||||
}
|
||||
static inline int unsetenv(const char *name)
|
||||
{
|
||||
return _putenv_s(name, "");
|
||||
}
|
||||
#endif
|
||||
@@ -26,6 +26,11 @@
|
||||
#include "Runtime.h"
|
||||
#include "RuntimePrivate.hpp"
|
||||
#include "Worker.h"
|
||||
#include "KString.h"
|
||||
|
||||
#ifndef KONAN_NO_THREADS
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
using kotlin::internal::FILE_NOT_INITIALIZED;
|
||||
using kotlin::internal::FILE_BEING_INITIALIZED;
|
||||
@@ -365,6 +370,35 @@ KBoolean Konan_Platform_getMemoryLeakChecker() {
|
||||
return g_checkLeaks;
|
||||
}
|
||||
|
||||
KInt Konan_Platform_getAvailableProcessors() {
|
||||
#ifdef KONAN_NO_THREADS
|
||||
return 1;
|
||||
#else
|
||||
auto res = std::thread::hardware_concurrency();
|
||||
// C++ standard says that if this function can return 0 if value is not "well defined or not computable"
|
||||
// In current libstdc++ implementation, seems it can happen only on unsupported targets.
|
||||
// We consider such systems as single-threaded
|
||||
if (res == 0) {
|
||||
res = 1;
|
||||
}
|
||||
// Probably it can't happen, but let's not allow overflows
|
||||
if (res > std::numeric_limits<int>::max()) {
|
||||
res = std::numeric_limits<int>::max();
|
||||
}
|
||||
return static_cast<KInt>(res);
|
||||
#endif
|
||||
}
|
||||
|
||||
OBJ_GETTER0(Konan_Platform_getAvailableProcessorsEnv) {
|
||||
char* env = getenv("KOTLIN_NATIVE_AVAILABLE_PROCESSORS");
|
||||
if (env == nullptr) {
|
||||
RETURN_OBJ(nullptr)
|
||||
}
|
||||
RETURN_RESULT_OF(CreateStringFromCString, env)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Konan_Platform_setMemoryLeakChecker(KBoolean value) {
|
||||
g_checkLeaks = value;
|
||||
}
|
||||
|
||||
@@ -102,6 +102,29 @@ public object Platform {
|
||||
public var isCleanersLeakCheckerActive: Boolean
|
||||
get() = Platform_getCleanersLeakChecker()
|
||||
set(value) = Platform_setCleanersLeakChecker(value)
|
||||
|
||||
/**
|
||||
* The number of logical processors available.
|
||||
*
|
||||
* Can be not equal to the number of processors in the system if some restrictions on processor usage were successfully detected.
|
||||
* Some kinds of processor usage restrictions are not detected, for now, e.g., CPU quotas in containers.
|
||||
*
|
||||
* The value is computed on each usage. It can change if some OS scheduler API restricts the process during runtime.
|
||||
* Also, value can differ on different threads if some thread-specific scheduler API was used.
|
||||
*
|
||||
* If one considers the value to be inaccurate and wants another one to be used, it can be overridden by
|
||||
* `KOTLIN_NATIVE_AVAILABLE_PROCESSORS` environment variable. When the variable is set and contains a value that is not
|
||||
* positive [Int], [IllegalStateException] will be thrown.
|
||||
*/
|
||||
@ExperimentalStdlibApi
|
||||
public fun getAvailableProcessors() : Int {
|
||||
val fromEnv = Platform_getAvailableProcessorsEnv()
|
||||
if (fromEnv == null) {
|
||||
return Platform_getAvailableProcessors()
|
||||
}
|
||||
return fromEnv.toIntOrNull()?.takeIf { it > 0 } ?:
|
||||
throw IllegalStateException("Available processors has incorrect environment override: $fromEnv")
|
||||
}
|
||||
}
|
||||
|
||||
@GCUnsafeCall("Konan_Platform_canAccessUnaligned")
|
||||
@@ -134,6 +157,13 @@ private external fun Platform_getCleanersLeakChecker(): Boolean
|
||||
@GCUnsafeCall("Konan_Platform_setCleanersLeakChecker")
|
||||
private external fun Platform_setCleanersLeakChecker(value: Boolean): Unit
|
||||
|
||||
@GCUnsafeCall("Konan_Platform_getAvailableProcessorsEnv")
|
||||
private external fun Platform_getAvailableProcessorsEnv(): String?
|
||||
|
||||
@GCUnsafeCall("Konan_Platform_getAvailableProcessors")
|
||||
private external fun Platform_getAvailableProcessors(): Int
|
||||
|
||||
|
||||
@TypedIntrinsic(IntrinsicType.IS_EXPERIMENTAL_MM)
|
||||
@ExperimentalStdlibApi
|
||||
external fun isExperimentalMM(): Boolean
|
||||
|
||||
@@ -52,8 +52,10 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"_ZSt28_Rb_tree_rebalance_for_erasePSt18_Rb_tree_node_baseRS_", // std::_Rb_tree_rebalance_for_erase(std::_Rb_tree_node_base*, std::_Rb_tree_node_base&)
|
||||
"_ZN9__gnu_cxx27__verbose_terminate_handlerEv", // __gnu_cxx::__verbose_terminate_handler()
|
||||
"_Znwm", // new
|
||||
"_Znwy",
|
||||
"_Znwy", // operator new(unsigned long long)
|
||||
"_ZdlPv", // delete
|
||||
"_ZNSt3__16thread20hardware_concurrencyEv", // std::__1::thread::hardware_concurrency()
|
||||
"_ZNSt6thread20hardware_concurrencyEv", // std::thread::hardware_concurrency()
|
||||
"__mingw_vsnprintf",
|
||||
"__cxa_allocate_exception",
|
||||
"__cxa_begin_catch",
|
||||
@@ -137,6 +139,10 @@ extern "C" const char* Kotlin_callsCheckerGoodFunctionNames[] = {
|
||||
"vsnprintf",
|
||||
"bcmp",
|
||||
|
||||
"getenv",
|
||||
"setenv",
|
||||
"unsetenv",
|
||||
|
||||
"dispatch_once",
|
||||
"\x01_pthread_cond_init",
|
||||
"_pthread_cond_init",
|
||||
|
||||
Reference in New Issue
Block a user