forked from bartvdbraak/blender
Add cross-platform NUMA library
Makes it simple to use NUMA libraries on various platforms.
This commit is contained in:
parent
9a5df92c1b
commit
683662e630
@ -687,6 +687,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
|
||||
|
||||
bf_intern_glew_mx
|
||||
bf_intern_clog
|
||||
bf_intern_numaapi
|
||||
)
|
||||
|
||||
if(NOT WITH_SYSTEM_GLOG)
|
||||
|
@ -30,6 +30,7 @@ add_subdirectory(ghost)
|
||||
add_subdirectory(guardedalloc)
|
||||
add_subdirectory(libmv)
|
||||
add_subdirectory(memutil)
|
||||
add_subdirectory(numaapi)
|
||||
add_subdirectory(opencolorio)
|
||||
add_subdirectory(mikktspace)
|
||||
add_subdirectory(glew-mx)
|
||||
|
1
intern/numaapi/AUTHORS
Normal file
1
intern/numaapi/AUTHORS
Normal file
@ -0,0 +1 @@
|
||||
Sergey Sharybin <sergey.vfx@gmail.com>
|
39
intern/numaapi/CMakeLists.txt
Normal file
39
intern/numaapi/CMakeLists.txt
Normal file
@ -0,0 +1,39 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
set(INC
|
||||
./include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC
|
||||
source/numaapi.c
|
||||
source/numaapi_linux.c
|
||||
source/numaapi_stub.c
|
||||
source/numaapi_win32.c
|
||||
|
||||
include/numaapi.h
|
||||
source/build_config.h
|
||||
)
|
||||
|
||||
add_definitions(-DWITH_DYNLOAD)
|
||||
|
||||
blender_add_lib(bf_intern_numaapi "${SRC}" "${INC}" "${INC_SYS}")
|
19
intern/numaapi/LICENSE
Normal file
19
intern/numaapi/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016 libnumaapi authors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
7
intern/numaapi/README
Normal file
7
intern/numaapi/README
Normal file
@ -0,0 +1,7 @@
|
||||
LibNumaAPI is aimed to provide one common cross-platform API for all
|
||||
possible platforms, so cross-platform applications might not worry
|
||||
about implementation details.
|
||||
|
||||
LICENSE
|
||||
|
||||
LibNumaAPI library is released under the MIT license.
|
5
intern/numaapi/README.blender
Normal file
5
intern/numaapi/README.blender
Normal file
@ -0,0 +1,5 @@
|
||||
Project: LibNumaAPI
|
||||
URL: https://github.com/Nazg-Gul/libNumaAPI
|
||||
License: MIT
|
||||
Upstream version: f83d41ec4d7
|
||||
Local modifications: None
|
108
intern/numaapi/include/numaapi.h
Normal file
108
intern/numaapi/include/numaapi.h
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2016, libnumaapi authors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
// Author: Sergey Sharybin (sergey.vfx@gmail.com)
|
||||
|
||||
#ifndef __LIBNUMAAPI_H__
|
||||
#define __LIBNUMAAPI_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NUMAAPI_VERSION_MAJOR 1
|
||||
#define NUMAAPI_VERSION_MINOR 0
|
||||
|
||||
typedef enum NUMAAPI_Result {
|
||||
NUMAAPI_SUCCESS = 0,
|
||||
// NUMA is not available on this platform.
|
||||
NUMAAPI_NOT_AVAILABLE = 1,
|
||||
// Generic error, no real details are available,
|
||||
NUMAAPI_ERROR = 2,
|
||||
// Error installing atexit() handlers.
|
||||
NUMAAPI_ERROR_ATEXIT = 3,
|
||||
} NUMAAPI_Result;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization.
|
||||
|
||||
// Initialize NUMA API.
|
||||
//
|
||||
// This is first call which should be called before any other NUMA functions
|
||||
// can be used.
|
||||
NUMAAPI_Result numaAPI_Initialize(void);
|
||||
|
||||
// Get string representation of NUMAPIResult.
|
||||
const char* numaAPI_ResultAsString(NUMAAPI_Result result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Topology query.
|
||||
|
||||
// Get number of available nodes.
|
||||
//
|
||||
// This is in fact an index of last node plus one and it's not guaranteed
|
||||
// that all nodes up to this one are available.
|
||||
int numaAPI_GetNumNodes(void);
|
||||
|
||||
// Returns truth if the given node is available for compute.
|
||||
bool numaAPI_IsNodeAvailable(int node);
|
||||
|
||||
// Getnumber of available processors on a given node.
|
||||
int numaAPI_GetNumNodeProcessors(int node);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Affinities.
|
||||
|
||||
// Runs the current process and its children on a specific node.
|
||||
//
|
||||
// Returns truth if affinity has successfully changed.
|
||||
//
|
||||
// NOTE: This function can not change active CPU group. Mainly designed to deal
|
||||
// with Threadripper 2 topology, to make it possible to gain maximum performance
|
||||
// for the main application thread.
|
||||
bool numaAPI_RunProcessOnNode(int node);
|
||||
|
||||
// Runs the current thread and its children on a specific node.
|
||||
//
|
||||
// Returns truth if affinity has successfully changed.
|
||||
bool numaAPI_RunThreadOnNode(int node);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory management.
|
||||
|
||||
// Allocate memory on a given node,
|
||||
void* numaAPI_AllocateOnNode(size_t size, int node);
|
||||
|
||||
// Allocate memory in the local memory, closest to the current node.
|
||||
void* numaAPI_AllocateLocal(size_t size);
|
||||
|
||||
// Frees size bytes of memory starting at start.
|
||||
//
|
||||
// TODO(sergey): Consider making it regular free() semantic.
|
||||
void numaAPI_Free(void* start, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __LIBNUMAAPI_H__
|
379
intern/numaapi/source/build_config.h
Normal file
379
intern/numaapi/source/build_config.h
Normal file
@ -0,0 +1,379 @@
|
||||
// Copyright (c) 2018, libnumaapi authors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
// Author: Sergey Sharybin (sergey.vfx@gmail.com)
|
||||
|
||||
#ifndef __BUILD_CONFIG_H__
|
||||
#define __BUILD_CONFIG_H__
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Initially is based on Chromium's build_config.h, with tweaks and extensions
|
||||
// needed for this project.
|
||||
//
|
||||
// NOTE: All commonly used symbols (which are checked on a "top" level, from
|
||||
// outside of any platform-specific ifdef block) are to be explicitly defined
|
||||
// to 0 when they are not "active". This is extra lines of code in this file,
|
||||
// but is not being edited that often. Such approach helps catching cases when
|
||||
// one attempted to access build configuration variable without including the
|
||||
// header by simply using -Wundef compiler attribute.
|
||||
//
|
||||
// NOTE: Not having things explicitly defined to 0 is harmless (in terms it
|
||||
// follows same rules as Google projects) and will simply cause compiler to
|
||||
// become more noisy, which is simple to correct.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// A set of macros to use for platform detection.
|
||||
|
||||
#if defined(__native_client__)
|
||||
// __native_client__ must be first, so that other OS_ defines are not set.
|
||||
# define OS_NACL 1
|
||||
#elif defined(_AIX)
|
||||
# define OS_AIX 1
|
||||
#elif defined(ANDROID)
|
||||
# define OS_ANDROID 1
|
||||
#elif defined(__APPLE__)
|
||||
// Only include TargetConditions after testing ANDROID as some android builds
|
||||
// on mac don't have this header available and it's not needed unless the target
|
||||
// is really mac/ios.
|
||||
# include <TargetConditionals.h>
|
||||
# define OS_MACOSX 1
|
||||
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
||||
# define OS_IOS 1
|
||||
# endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
|
||||
#elif defined(__HAIKU__)
|
||||
# define OS_HAIKU 1
|
||||
#elif defined(__hpux)
|
||||
# define OS_HPUX 1
|
||||
#elif defined(__linux__)
|
||||
# define OS_LINUX 1
|
||||
// Include a system header to pull in features.h for glibc/uclibc macros.
|
||||
# include <unistd.h>
|
||||
# if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
// We really are using glibc, not uClibc pretending to be glibc.
|
||||
# define LIBC_GLIBC 1
|
||||
# endif
|
||||
#elif defined(__sgi)
|
||||
# define OS_IRIX 1
|
||||
#elif defined(_WIN32)
|
||||
# define OS_WIN 1
|
||||
#elif defined(__FreeBSD__)
|
||||
# define OS_FREEBSD 1
|
||||
#elif defined(__NetBSD__)
|
||||
# define OS_NETBSD 1
|
||||
#elif defined(__OpenBSD__)
|
||||
# define OS_OPENBSD 1
|
||||
#elif defined(__sun)
|
||||
# define OS_SOLARIS 1
|
||||
#elif defined(__QNXNTO__)
|
||||
# define OS_QNX 1
|
||||
#else
|
||||
# error Please add support for your platform in build_config.h
|
||||
#endif
|
||||
|
||||
#if !defined(OS_AIX)
|
||||
# define OS_AIX 0
|
||||
#endif
|
||||
#if !defined(OS_NACL)
|
||||
# define OS_NACL 0
|
||||
#endif
|
||||
#if !defined(OS_ANDROID)
|
||||
# define OS_ANDROID 0
|
||||
#endif
|
||||
#if !defined(OS_MACOSX)
|
||||
# define OS_MACOSX 0
|
||||
#endif
|
||||
#if !defined(OS_IOS)
|
||||
# define OS_IOS 0
|
||||
#endif
|
||||
#if !defined(OS_HAIKU)
|
||||
# define OS_HAIKU 0
|
||||
#endif
|
||||
#if !defined(OS_HPUX)
|
||||
# define OS_HPUX 0
|
||||
#endif
|
||||
#if !defined(OS_IRIX)
|
||||
# define OS_IRIX 0
|
||||
#endif
|
||||
#if !defined(OS_LINUX)
|
||||
# define OS_LINUX 0
|
||||
#endif
|
||||
#if !defined(LIBC_GLIBC)
|
||||
# define LIBC_GLIBC 0
|
||||
#endif
|
||||
#if !defined(OS_WIN)
|
||||
# define OS_WIN 0
|
||||
#endif
|
||||
#if !defined(OS_FREEBSD)
|
||||
# define OS_FREEBSD 0
|
||||
#endif
|
||||
#if !defined(OS_NETBSD)
|
||||
# define OS_NETBSD 0
|
||||
#endif
|
||||
#if !defined(OS_OPENBSD)
|
||||
# define OS_OPENBSD 0
|
||||
#endif
|
||||
#if !defined(OS_SOLARIS)
|
||||
# define OS_SOLARIS 0
|
||||
#endif
|
||||
#if !defined(OS_QNX)
|
||||
# define OS_QNX 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// *BSD OS family detection.
|
||||
//
|
||||
// For access to standard BSD features, use OS_BSD instead of a
|
||||
// more specific macro.
|
||||
#if OS_FREEBSD || OS_OPENBSD || OS_NETBSD
|
||||
# define OS_BSD 1
|
||||
#else
|
||||
# define OS_BSD 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// POSIX system detection.
|
||||
//
|
||||
// For access to standard POSIXish features use OS_POSIX instead of a
|
||||
// more specific macro.
|
||||
#if OS_MACOSX || OS_LINUX || OS_BSD || OS_SOLARIS ||OS_ANDROID || OS_NACL || \
|
||||
OS_QNX || OS_HAIKU || OS_AIX || OS_HPUX || OS_IRIX
|
||||
# define OS_POSIX 1
|
||||
#else
|
||||
# define OS_POSIX 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Compiler detection, including its capabilities.
|
||||
|
||||
#if defined(__clang__)
|
||||
# define COMPILER_CLANG 1
|
||||
#elif defined(__GNUC__)
|
||||
# define COMPILER_GCC 1
|
||||
# define COMPILER_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#elif defined(_MSC_VER)
|
||||
# define COMPILER_MSVC 1
|
||||
# define COMPILER_MSVC_VERSION (_MSC_VER)
|
||||
#elif defined(__MINGW32__)
|
||||
# define COMPILER_MINGW32 1
|
||||
#elif defined(__MINGW64__)
|
||||
# define COMPILER_MINGW64 1
|
||||
#else
|
||||
# error Please add support for your compiler in build_config.h
|
||||
#endif
|
||||
|
||||
#if !defined(COMPILER_CLANG)
|
||||
# define COMPILER_CLANG 0
|
||||
#endif
|
||||
#if !defined(COMPILER_GCC)
|
||||
# define COMPILER_GCC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_MSVC)
|
||||
# define COMPILER_MSVC 0
|
||||
#endif
|
||||
#if !defined(COMPILER_MINGW32)
|
||||
# define COMPILER_MINGW32 0
|
||||
#endif
|
||||
#if !defined(COMPILER_MINGW64)
|
||||
# define COMPILER_MINGW64 0
|
||||
#endif
|
||||
|
||||
// Compiler is any of MinGW family.
|
||||
#if COMPILER_MINGW32 || COMPILER_MINGW64
|
||||
# define COMPILER_MINGW 1
|
||||
#else
|
||||
# define COMPILER_MINGW 0
|
||||
#endif
|
||||
|
||||
// Check what is the latest C++ specification the compiler supports.
|
||||
//
|
||||
// NOTE: Use explicit definition here to avoid expansion-to-defined warning from
|
||||
// being geenrated. While this will most likely a false-positive warning in this
|
||||
// particular case, that warning might be helpful to catch errors elsewhere.
|
||||
|
||||
// C++11 check.
|
||||
#if ((defined(__cplusplus) && (__cplusplus > 199711L)) || \
|
||||
(defined(_MSC_VER) && (_MSC_VER >= 1800)))
|
||||
# define COMPILER_SUPPORTS_CXX11 1
|
||||
#else
|
||||
# define COMPILER_SUPPORTS_CXX11 0
|
||||
#endif
|
||||
// C++14 check.
|
||||
#if (defined(__cplusplus) && (__cplusplus > 201311L))
|
||||
# define COMPILER_SUPPORTS_CXX14 1
|
||||
#else
|
||||
# define COMPILER_SUPPORTS_CXX14 0
|
||||
#endif
|
||||
// C++17 check.
|
||||
#if (defined(__cplusplus) && (__cplusplus > 201611L))
|
||||
# define COMPILER_SUPPORTS_CXX17 1
|
||||
#else
|
||||
# define COMPILER_SUPPORTS_CXX17 0
|
||||
#endif
|
||||
// C++20 check.
|
||||
#if (defined(__cplusplus) && (__cplusplus > 201911L))
|
||||
# define COMPILER_SUPPORTS_CXX20 1
|
||||
#else
|
||||
# define COMPILER_SUPPORTS_CXX20 0
|
||||
#endif
|
||||
|
||||
// COMPILER_USE_ADDRESS_SANITIZER is defined when program is detected that
|
||||
// compilation happened wit haddress sanitizer enabled. This allows to give
|
||||
// tips to sanitizer, or maybe work around some known issues with third party
|
||||
// libraries.
|
||||
#if !defined(COMPILER_USE_ADDRESS_SANITIZER)
|
||||
# if defined(__has_feature)
|
||||
# define COMPILER_USE_ADDRESS_SANITIZER 1
|
||||
# elif defined(__SANITIZE_ADDRESS__)
|
||||
# define COMPILER_USE_ADDRESS_SANITIZER 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(COMPILER_USE_ADDRESS_SANITIZER)
|
||||
# define COMPILER_USE_ADDRESS_SANITIZER 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Processor architecture detection.
|
||||
//
|
||||
// For more info on what's defined, see:
|
||||
//
|
||||
// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
|
||||
// http://www.agner.org/optimize/calling_conventions.pdf
|
||||
//
|
||||
// or with gcc, run: "echo | gcc -E -dM -"
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
# define ARCH_CPU_X86_FAMILY 1
|
||||
# define ARCH_CPU_X86_64 1
|
||||
# define ARCH_CPU_64_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
# define ARCH_CPU_X86_FAMILY 1
|
||||
# define ARCH_CPU_X86 1
|
||||
# define ARCH_CPU_32_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
#elif defined(__ARMEL__)
|
||||
# define ARCH_CPU_ARM_FAMILY 1
|
||||
# define ARCH_CPU_ARMEL 1
|
||||
# define ARCH_CPU_32_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
#elif defined(__aarch64__)
|
||||
# define ARCH_CPU_ARM_FAMILY 1
|
||||
# define ARCH_CPU_ARM64 1
|
||||
# define ARCH_CPU_64_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
#elif defined(__pnacl__)
|
||||
# define ARCH_CPU_32_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
#elif defined(__MIPSEL__)
|
||||
# if defined(__LP64__)
|
||||
# define ARCH_CPU_MIPS64_FAMILY 1
|
||||
# define ARCH_CPU_MIPS64EL 1
|
||||
# define ARCH_CPU_64_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
# else
|
||||
# define ARCH_CPU_MIPS_FAMILY 1
|
||||
# define ARCH_CPU_MIPSEL 1
|
||||
# define ARCH_CPU_32_BITS 1
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
# endif
|
||||
#elif defined(__MIPSEB__)
|
||||
# if defined(__LP64__)
|
||||
# define ARCH_CPU_MIPS64_FAMILY 1
|
||||
# define ARCH_CPU_MIPS64EB 1
|
||||
# define ARCH_CPU_64_BITS 1
|
||||
# define ARCH_CPU_BIG_ENDIAN 1
|
||||
# else
|
||||
# define ARCH_CPU_MIPS_FAMILY 1
|
||||
# define ARCH_CPU_MIPSEB 1
|
||||
# define ARCH_CPU_32_BITS 1
|
||||
# define ARCH_CPU_BIG_ENDIAN 1
|
||||
# endif
|
||||
#else
|
||||
# error Please add support for your architecture in build_config.h
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_CPU_LITTLE_ENDIAN)
|
||||
# define ARCH_CPU_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_BIG_ENDIAN)
|
||||
# define ARCH_CPU_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_CPU_32_BITS)
|
||||
# define ARCH_CPU_32_BITS 0
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_64_BITS)
|
||||
# define ARCH_CPU_64_BITS 0
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_CPU_X86_FAMILY)
|
||||
# define ARCH_CPU_X86_FAMILY 0
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_ARM_FAMILY)
|
||||
# define ARCH_CPU_ARM_FAMILY 0
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_MIPS_FAMILY)
|
||||
# define ARCH_CPU_MIPS_FAMILY 0
|
||||
#endif
|
||||
#if !defined(ARCH_CPU_MIPS64_FAMILY)
|
||||
# define ARCH_CPU_MIPS64_FAMILY 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Sizes of platform-dependent types.
|
||||
|
||||
#if defined(__SIZEOF_POINTER__)
|
||||
# define PLATFORM_SIZEOF_PTR __SIZEOF_POINTER__
|
||||
#elif defined(UINTPTR_MAX)
|
||||
# if (UINTPTR_MAX == 0xffffffff)
|
||||
# define PLATFORM_SIZEOF_PTR 4
|
||||
# elif (UINTPTR_MAX == 0xffffffffffffffff) // NOLINT
|
||||
# define PLATFORM_SIZEOF_PTR 8
|
||||
# endif
|
||||
#elif defined(__WORDSIZE)
|
||||
# if (__WORDSIZE == 32)
|
||||
# define PLATFORM_SIZEOF_PTR 4
|
||||
# else if (__WORDSIZE == 64)
|
||||
# define PLATFORM_SIZEOF_PTR 8
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(PLATFORM_SIZEOF_PTR)
|
||||
# error "Cannot find pointer size"
|
||||
#endif
|
||||
|
||||
#if (UINT_MAX == 0xffffffff)
|
||||
# define PLATFORM_SIZEOF_INT 4
|
||||
#elif (UINT_MAX == 0xffffffffffffffff) // NOLINT
|
||||
# define PLATFORM_SIZEOF_INT 8
|
||||
#else
|
||||
# error "Cannot find int size"
|
||||
#endif
|
||||
|
||||
#if (USHRT_MAX == 0xffffffff)
|
||||
# define PLATFORM_SIZEOF_SHORT 4
|
||||
#elif (USHRT_MAX == 0xffff) // NOLINT
|
||||
# define PLATFORM_SIZEOF_SHORT 2
|
||||
#else
|
||||
# error "Cannot find short size"
|
||||
#endif
|
||||
|
||||
#endif // __BUILD_CONFIG_H__
|
37
intern/numaapi/source/numaapi.c
Normal file
37
intern/numaapi/source/numaapi.c
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2018, libnumaapi authors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
// Author: Sergey Sharybin (sergey.vfx@gmail.com)
|
||||
|
||||
#include "numaapi.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// Get string representation of NUMAPIResult.
|
||||
const char* numaAPI_ResultAsString(NUMAAPI_Result result) {
|
||||
switch (result) {
|
||||
case NUMAAPI_SUCCESS: return "SUCCESS";
|
||||
case NUMAAPI_NOT_AVAILABLE: return "NOT_AVAILABLE";
|
||||
case NUMAAPI_ERROR: return "ERROR";
|
||||
case NUMAAPI_ERROR_ATEXIT: return "ERROR_AT_EXIT";
|
||||
}
|
||||
assert(!"Unknown result was passed to numapi_ResultAsString().");
|
||||
return "UNKNOWN";
|
||||
}
|
272
intern/numaapi/source/numaapi_linux.c
Normal file
272
intern/numaapi/source/numaapi_linux.c
Normal file
@ -0,0 +1,272 @@
|
||||
// Copyright (c) 2016, libnumaapi authors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
// Author: Sergey Sharybin (sergey.vfx@gmail.com)
|
||||
|
||||
#include "build_config.h"
|
||||
|
||||
#if OS_LINUX
|
||||
|
||||
#include "numaapi.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef WITH_DYNLOAD
|
||||
# include <numa.h>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DYNLOAD
|
||||
|
||||
// Descriptor numa library.
|
||||
static void* numa_lib;
|
||||
|
||||
// Types of all symbols which are read from the library.
|
||||
struct bitmask;
|
||||
typedef int tnuma_available(void);
|
||||
typedef int tnuma_max_node(void);
|
||||
typedef int tnuma_node_to_cpus(int node, struct bitmask* mask);
|
||||
typedef long tnuma_node_size(int node, long* freep);
|
||||
typedef int tnuma_run_on_node(int node);
|
||||
typedef void* tnuma_alloc_onnode(size_t size, int node);
|
||||
typedef void* tnuma_alloc_local(size_t size);
|
||||
typedef void tnuma_free(void* start, size_t size);
|
||||
typedef struct bitmask* tnuma_bitmask_clearall(struct bitmask *bitmask);
|
||||
typedef int tnuma_bitmask_isbitset(const struct bitmask *bitmask,
|
||||
unsigned int n);
|
||||
typedef struct bitmask* tnuma_bitmask_setbit(struct bitmask *bitmask,
|
||||
unsigned int n);
|
||||
typedef unsigned int tnuma_bitmask_nbytes(struct bitmask *bitmask);
|
||||
typedef void tnuma_bitmask_free(struct bitmask *bitmask);
|
||||
typedef struct bitmask* tnuma_allocate_cpumask(void);
|
||||
typedef struct bitmask* tnuma_allocate_nodemask(void);
|
||||
typedef void tnuma_free_cpumask(struct bitmask* bitmask);
|
||||
typedef void tnuma_free_nodemask(struct bitmask* bitmask);
|
||||
typedef int tnuma_run_on_node_mask(struct bitmask *nodemask);
|
||||
typedef void tnuma_set_interleave_mask(struct bitmask *nodemask);
|
||||
typedef void tnuma_set_localalloc(void);
|
||||
|
||||
// Actual symbols.
|
||||
static tnuma_available* numa_available;
|
||||
static tnuma_max_node* numa_max_node;
|
||||
static tnuma_node_to_cpus* numa_node_to_cpus;
|
||||
static tnuma_node_size* numa_node_size;
|
||||
static tnuma_run_on_node* numa_run_on_node;
|
||||
static tnuma_alloc_onnode* numa_alloc_onnode;
|
||||
static tnuma_alloc_local* numa_alloc_local;
|
||||
static tnuma_free* numa_free;
|
||||
static tnuma_bitmask_clearall* numa_bitmask_clearall;
|
||||
static tnuma_bitmask_isbitset* numa_bitmask_isbitset;
|
||||
static tnuma_bitmask_setbit* numa_bitmask_setbit;
|
||||
static tnuma_bitmask_nbytes* numa_bitmask_nbytes;
|
||||
static tnuma_bitmask_free* numa_bitmask_free;
|
||||
static tnuma_allocate_cpumask* numa_allocate_cpumask;
|
||||
static tnuma_allocate_nodemask* numa_allocate_nodemask;
|
||||
static tnuma_free_nodemask* numa_free_nodemask;
|
||||
static tnuma_free_cpumask* numa_free_cpumask;
|
||||
static tnuma_run_on_node_mask* numa_run_on_node_mask;
|
||||
static tnuma_set_interleave_mask* numa_set_interleave_mask;
|
||||
static tnuma_set_localalloc* numa_set_localalloc;
|
||||
|
||||
static void* findLibrary(const char** paths) {
|
||||
int i = 0;
|
||||
while (paths[i] != NULL) {
|
||||
void* lib = dlopen(paths[i], RTLD_LAZY);
|
||||
if (lib != NULL) {
|
||||
return lib;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void numaExit(void) {
|
||||
if (numa_lib == NULL) {
|
||||
return;
|
||||
}
|
||||
dlclose(numa_lib);
|
||||
numa_lib = NULL;
|
||||
}
|
||||
|
||||
static NUMAAPI_Result loadNumaSymbols(void) {
|
||||
// Prevent multiple initializations.
|
||||
static bool initialized = false;
|
||||
static NUMAAPI_Result result = NUMAAPI_NOT_AVAILABLE;
|
||||
if (initialized) {
|
||||
return result;
|
||||
}
|
||||
initialized = true;
|
||||
// Find appropriate .so library.
|
||||
const char* numa_paths[] = {
|
||||
"libnuma.so.1",
|
||||
"libnuma.so",
|
||||
NULL};
|
||||
// Register de-initialization.
|
||||
const int error = atexit(numaExit);
|
||||
if (error) {
|
||||
result = NUMAAPI_ERROR_ATEXIT;
|
||||
return result;
|
||||
}
|
||||
// Load library.
|
||||
numa_lib = findLibrary(numa_paths);
|
||||
if (numa_lib == NULL) {
|
||||
result = NUMAAPI_NOT_AVAILABLE;
|
||||
return result;
|
||||
}
|
||||
// Load symbols.
|
||||
|
||||
#define _LIBRARY_FIND(lib, name) \
|
||||
do { \
|
||||
name = (t##name *)dlsym(lib, #name); \
|
||||
} while (0)
|
||||
#define NUMA_LIBRARY_FIND(name) _LIBRARY_FIND(numa_lib, name)
|
||||
|
||||
NUMA_LIBRARY_FIND(numa_available);
|
||||
NUMA_LIBRARY_FIND(numa_max_node);
|
||||
NUMA_LIBRARY_FIND(numa_node_to_cpus);
|
||||
NUMA_LIBRARY_FIND(numa_node_size);
|
||||
NUMA_LIBRARY_FIND(numa_run_on_node);
|
||||
NUMA_LIBRARY_FIND(numa_alloc_onnode);
|
||||
NUMA_LIBRARY_FIND(numa_alloc_local);
|
||||
NUMA_LIBRARY_FIND(numa_free);
|
||||
NUMA_LIBRARY_FIND(numa_bitmask_clearall);
|
||||
NUMA_LIBRARY_FIND(numa_bitmask_isbitset);
|
||||
NUMA_LIBRARY_FIND(numa_bitmask_setbit);
|
||||
NUMA_LIBRARY_FIND(numa_bitmask_nbytes);
|
||||
NUMA_LIBRARY_FIND(numa_bitmask_free);
|
||||
NUMA_LIBRARY_FIND(numa_allocate_cpumask);
|
||||
NUMA_LIBRARY_FIND(numa_allocate_nodemask);
|
||||
NUMA_LIBRARY_FIND(numa_free_cpumask);
|
||||
NUMA_LIBRARY_FIND(numa_free_nodemask);
|
||||
NUMA_LIBRARY_FIND(numa_run_on_node_mask);
|
||||
NUMA_LIBRARY_FIND(numa_set_interleave_mask);
|
||||
NUMA_LIBRARY_FIND(numa_set_localalloc);
|
||||
|
||||
#undef NUMA_LIBRARY_FIND
|
||||
#undef _LIBRARY_FIND
|
||||
|
||||
result = NUMAAPI_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization.
|
||||
|
||||
NUMAAPI_Result numaAPI_Initialize(void) {
|
||||
#ifdef WITH_DYNLOAD
|
||||
NUMAAPI_Result result = loadNumaSymbols();
|
||||
if (result != NUMAAPI_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
if (numa_available() < 0) {
|
||||
return NUMAAPI_NOT_AVAILABLE;
|
||||
}
|
||||
return NUMAAPI_SUCCESS;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Topology query.
|
||||
|
||||
int numaAPI_GetNumNodes(void) {
|
||||
return numa_max_node() + 1;
|
||||
}
|
||||
|
||||
bool numaAPI_IsNodeAvailable(int node) {
|
||||
if (numa_node_size(node, NULL) > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int numaAPI_GetNumNodeProcessors(int node) {
|
||||
struct bitmask* cpu_mask = numa_allocate_cpumask();
|
||||
numa_node_to_cpus(node, cpu_mask);
|
||||
const unsigned int num_bytes = numa_bitmask_nbytes(cpu_mask);
|
||||
const unsigned int num_bits = num_bytes *8;
|
||||
// TODO(sergey): There might be faster way calculating number of set bits.
|
||||
int num_processors = 0;
|
||||
for (unsigned int bit = 0; bit < num_bits; ++bit) {
|
||||
if (numa_bitmask_isbitset(cpu_mask, bit)) {
|
||||
++num_processors;
|
||||
}
|
||||
}
|
||||
#ifdef WITH_DYNLOAD
|
||||
if (numa_free_cpumask != NULL) {
|
||||
numa_free_cpumask(cpu_mask);
|
||||
} else {
|
||||
numa_bitmask_free(cpu_mask);
|
||||
}
|
||||
#else
|
||||
numa_free_cpumask(cpu_mask);
|
||||
#endif
|
||||
return num_processors;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Affinities.
|
||||
|
||||
bool numaAPI_RunProcessOnNode(int node) {
|
||||
numaAPI_RunThreadOnNode(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool numaAPI_RunThreadOnNode(int node) {
|
||||
// Construct bit mask from node index.
|
||||
struct bitmask* node_mask = numa_allocate_nodemask();
|
||||
numa_bitmask_clearall(node_mask);
|
||||
numa_bitmask_setbit(node_mask, node);
|
||||
numa_run_on_node_mask(node_mask);
|
||||
// TODO(sergey): The following commands are based on x265 code, we might want
|
||||
// to make those optional, or require to call those explicitly.
|
||||
//
|
||||
// Current assumption is that this is similar to SetThreadGroupAffinity().
|
||||
numa_set_interleave_mask(node_mask);
|
||||
numa_set_localalloc();
|
||||
#ifdef WITH_DYNLOAD
|
||||
if (numa_free_nodemask != NULL) {
|
||||
numa_free_nodemask(node_mask);
|
||||
} else {
|
||||
numa_bitmask_free(node_mask);
|
||||
}
|
||||
#else
|
||||
numa_free_nodemask(node_mask);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory management.
|
||||
|
||||
void* numaAPI_AllocateOnNode(size_t size, int node) {
|
||||
return numa_alloc_onnode(size, node);
|
||||
}
|
||||
|
||||
void* numaAPI_AllocateLocal(size_t size) {
|
||||
return numa_alloc_local(size);
|
||||
}
|
||||
|
||||
void numaAPI_Free(void* start, size_t size) {
|
||||
numa_free(start, size);
|
||||
}
|
||||
|
||||
#endif // OS_LINUX
|
82
intern/numaapi/source/numaapi_stub.c
Normal file
82
intern/numaapi/source/numaapi_stub.c
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2016, libnumaapi authors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
// Author: Sergey Sharybin (sergey.vfx@gmail.com)
|
||||
|
||||
#include "numaapi.h"
|
||||
|
||||
#include "build_config.h"
|
||||
|
||||
// Stub implementation for platforms which doesn't have NUMA support.
|
||||
|
||||
#if !OS_LINUX && !OS_WIN
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization.
|
||||
|
||||
NUMAPIResult numaAPI_Initialize(void) {
|
||||
return UMAAPI_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Topology query.
|
||||
|
||||
int numaAPI_GetNumNodes(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool numApiIsNodeAvailable(int node) {
|
||||
(void) node; // Ignored.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Affinities.
|
||||
|
||||
bool numaAPI_RunProcessOnNode(int node) {
|
||||
(void) node; // Ignored.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool numaAPI_RunThreadOnNode(int node) {
|
||||
(void) node; // Ignored.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory management.
|
||||
|
||||
void* numaAPI_AllocateOnNode(size_t size, int node) {
|
||||
(void) size; // Ignored.
|
||||
(void) node; // Ignored.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* numaAPI_AllocateLocal(size_t size) {
|
||||
(void) size; // Ignored.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void numaAPI_Free(void* start, size_t size) {
|
||||
(void) start; // Ignored.
|
||||
(void) size; // Ignored.
|
||||
}
|
||||
|
||||
#endif // !OS_LINUX && !OS_WIN
|
253
intern/numaapi/source/numaapi_win32.c
Normal file
253
intern/numaapi/source/numaapi_win32.c
Normal file
@ -0,0 +1,253 @@
|
||||
// Copyright (c) 2016, libnumaapi authors
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//
|
||||
// Author: Sergey Sharybin (sergey.vfx@gmail.com)
|
||||
|
||||
#include "build_config.h"
|
||||
|
||||
#if OS_WIN
|
||||
|
||||
#include "numaapi.h"
|
||||
|
||||
#ifndef NOGDI
|
||||
# define NOGDI
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOCOMM
|
||||
# define NOCOMM
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#if ARCH_CPU_64_BITS
|
||||
# include <VersionHelpers.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization.
|
||||
|
||||
// Kernel library, from where the symbols come.
|
||||
static HMODULE kernel_lib;
|
||||
|
||||
// Types of all symbols which are read from the library.
|
||||
|
||||
// NUMA function types.
|
||||
typedef BOOL t_GetNumaHighestNodeNumber(PULONG highest_node_number);
|
||||
typedef BOOL t_GetNumaNodeProcessorMask(UCHAR node, ULONGLONG* processor_mask);
|
||||
typedef BOOL t_GetNumaNodeProcessorMaskEx(USHORT node,
|
||||
GROUP_AFFINITY* processor_mask);
|
||||
typedef BOOL t_GetNumaProcessorNode(UCHAR processor, UCHAR* node_number);
|
||||
typedef void* t_VirtualAllocExNuma(HANDLE process_handle,
|
||||
LPVOID address,
|
||||
SIZE_T size,
|
||||
DWORD allocation_type,
|
||||
DWORD protect,
|
||||
DWORD preferred);
|
||||
typedef BOOL t_VirtualFree(void* address, SIZE_T size, DWORD free_type);
|
||||
// Threading function types.
|
||||
typedef BOOL t_SetProcessAffinityMask(HANDLE process_handle,
|
||||
DWORD_PTR process_affinity_mask);
|
||||
typedef BOOL t_SetThreadGroupAffinity(HANDLE thread_handle,
|
||||
const GROUP_AFFINITY* GroupAffinity,
|
||||
GROUP_AFFINITY* PreviousGroupAffinity);
|
||||
typedef DWORD t_GetCurrentProcessorNumber(void);
|
||||
|
||||
// NUMA symbols.
|
||||
static t_GetNumaHighestNodeNumber* _GetNumaHighestNodeNumber;
|
||||
static t_GetNumaNodeProcessorMask* _GetNumaNodeProcessorMask;
|
||||
static t_GetNumaNodeProcessorMaskEx* _GetNumaNodeProcessorMaskEx;
|
||||
static t_GetNumaProcessorNode* _GetNumaProcessorNode;
|
||||
static t_VirtualAllocExNuma* _VirtualAllocExNuma;
|
||||
static t_VirtualFree* _VirtualFree;
|
||||
// Threading symbols.
|
||||
static t_SetProcessAffinityMask* _SetProcessAffinityMask;
|
||||
static t_SetThreadGroupAffinity* _SetThreadGroupAffinity;
|
||||
static t_GetCurrentProcessorNumber* _GetCurrentProcessorNumber;
|
||||
|
||||
static void numaExit(void) {
|
||||
// TODO(sergey): Consider closing library here.
|
||||
}
|
||||
|
||||
static NUMAAPI_Result loadNumaSymbols(void) {
|
||||
// Prevent multiple initializations.
|
||||
static bool initialized = false;
|
||||
static NUMAAPI_Result result = NUMAAPI_NOT_AVAILABLE;
|
||||
if (initialized) {
|
||||
return result;
|
||||
}
|
||||
initialized = true;
|
||||
// Register de-initialization.
|
||||
const int error = atexit(numaExit);
|
||||
if (error) {
|
||||
result = NUMAAPI_ERROR_ATEXIT;
|
||||
return result;
|
||||
}
|
||||
// Load library.
|
||||
kernel_lib = LoadLibraryA("Kernel32.dll");
|
||||
// Load symbols.
|
||||
|
||||
#define _LIBRARY_FIND(lib, name) \
|
||||
do { \
|
||||
_##name = (t_##name *)GetProcAddress(lib, #name); \
|
||||
} while (0)
|
||||
#define KERNEL_LIBRARY_FIND(name) _LIBRARY_FIND(kernel_lib, name)
|
||||
|
||||
// NUMA.
|
||||
KERNEL_LIBRARY_FIND(GetNumaHighestNodeNumber);
|
||||
KERNEL_LIBRARY_FIND(GetNumaNodeProcessorMask);
|
||||
KERNEL_LIBRARY_FIND(GetNumaNodeProcessorMaskEx);
|
||||
KERNEL_LIBRARY_FIND(GetNumaProcessorNode);
|
||||
KERNEL_LIBRARY_FIND(VirtualAllocExNuma);
|
||||
KERNEL_LIBRARY_FIND(VirtualFree);
|
||||
// Threading.
|
||||
KERNEL_LIBRARY_FIND(SetProcessAffinityMask);
|
||||
KERNEL_LIBRARY_FIND(SetThreadGroupAffinity);
|
||||
KERNEL_LIBRARY_FIND(GetCurrentProcessorNumber);
|
||||
|
||||
#undef KERNEL_LIBRARY_FIND
|
||||
#undef _LIBRARY_FIND
|
||||
|
||||
result = NUMAAPI_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
NUMAAPI_Result numaAPI_Initialize(void) {
|
||||
#if !ARCH_CPU_64_BITS
|
||||
// No NUMA on 32 bit platforms.
|
||||
return LIBNUMAAPI_NOT_AVAILABLE;
|
||||
#else
|
||||
if (!IsWindows7OrGreater()) {
|
||||
// Require Windows 7 or higher.
|
||||
NUMAAPI_NOT_AVAILABLE;
|
||||
}
|
||||
loadNumaSymbols();
|
||||
return NUMAAPI_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Topology query.
|
||||
|
||||
int numaAPI_GetNumNodes(void) {
|
||||
ULONG highest_node_number;
|
||||
if (!_GetNumaHighestNodeNumber(&highest_node_number)) {
|
||||
return 0;
|
||||
}
|
||||
// TODO(sergey): Resolve the type narrowing.
|
||||
// NOTE: This is not necessarily a total amount of nodes in the system.
|
||||
return (int)highest_node_number + 1;
|
||||
}
|
||||
|
||||
bool numaAPI_IsNodeAvailable(int node) {
|
||||
// Trick to detect whether the node is usable or not: check whether
|
||||
// there are any processors associated with it.
|
||||
//
|
||||
// This is needed because numaApiGetNumNodes() is not guaranteed to
|
||||
// give total amount of nodes and some nodes might be unavailable.
|
||||
ULONGLONG processor_mask;
|
||||
if (!_GetNumaNodeProcessorMask(node, &processor_mask)) {
|
||||
return false;
|
||||
}
|
||||
if (processor_mask == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int numaAPI_GetNumNodeProcessors(int node) {
|
||||
ULONGLONG processor_mask;
|
||||
if (!_GetNumaNodeProcessorMask(node, &processor_mask)) {
|
||||
return 0;
|
||||
}
|
||||
// TODO(sergey): There might be faster way calculating number of set bits.
|
||||
int num_processors = 0;
|
||||
while (processor_mask != 0) {
|
||||
num_processors += (processor_mask & 1);
|
||||
processor_mask = (processor_mask >> 1);
|
||||
}
|
||||
return num_processors;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Affinities.
|
||||
|
||||
bool numaAPI_RunProcessOnNode(int node) {
|
||||
// TODO(sergey): Make sure requested node is within active CPU group.
|
||||
// Change affinity of the proces to make it to run on a given node.
|
||||
HANDLE process_handle = GetCurrentProcess();
|
||||
ULONGLONG processor_mask;
|
||||
if (_GetNumaNodeProcessorMask(node, &processor_mask) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (_SetProcessAffinityMask(process_handle, processor_mask) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool numaAPI_RunThreadOnNode(int node) {
|
||||
HANDLE thread_handle = GetCurrentThread();
|
||||
GROUP_AFFINITY group_affinity = { 0 };
|
||||
if (_GetNumaNodeProcessorMaskEx(node, &group_affinity) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (_SetThreadGroupAffinity(thread_handle, &group_affinity, NULL) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory management.
|
||||
|
||||
void* numaAPI_AllocateOnNode(size_t size, int node) {
|
||||
return _VirtualAllocExNuma(GetCurrentProcess(),
|
||||
NULL,
|
||||
size,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE,
|
||||
node);
|
||||
}
|
||||
|
||||
void* numaAPI_AllocateLocal(size_t size) {
|
||||
UCHAR current_processor = (UCHAR)_GetCurrentProcessorNumber();
|
||||
UCHAR node;
|
||||
if (!_GetNumaProcessorNode(current_processor, &node)) {
|
||||
return NULL;
|
||||
}
|
||||
return numaAPI_AllocateOnNode(size, node);
|
||||
}
|
||||
|
||||
void numaAPI_Free(void* start, size_t size) {
|
||||
if (!_VirtualFree(start, size, MEM_RELEASE)) {
|
||||
// TODO(sergey): Throw an error!
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OS_WIN
|
Loading…
Reference in New Issue
Block a user