before merge

This commit is contained in:
2026-10-12 04:13:46 +08:00
27 changed files with 797 additions and 1607 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
CompileFlags:
CompilationDatabase: ../..
CompilationDatabase: .
+3 -3
View File
@@ -53,11 +53,11 @@ does not cross-compile the C library.
## clangd in VS Code
The `.clangd` file searches for `compile_commands.json` at the repository root.
The `.clangd` file searches for `compile_commands.json` in `src/Nitload.Native`.
When using CMake Tools, set `cmake.copyCompileCommands` to
`${workspaceFolder}/compile_commands.json` so the active Debug or Release preset
`${workspaceFolder}/src/Nitload.Native/compile_commands.json` so the active Debug or Release preset
updates that file after configuration. For command-line configuration, copy
`cmake_build/<preset>/compile_commands.json` to the repository root. Restart
`cmake_build/<preset>/compile_commands.json` to `src/Nitload.Native`. Restart
clangd after changing the database or renaming headers.
## Code Layout
+76 -8
View File
@@ -26,9 +26,18 @@ typedef struct nfn_linux_max_context {
int max_value;
} nfn_linux_max_context;
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.linux.c
typedef struct nfn_linux_fill_cpu_context {
uint64_t *internal;
uint32_t *global;
=======
typedef struct nif_linux_fill_cpu_context {
uint32_t *processor_group_ids;
uint32_t *socket_ids;
uint32_t *cpu_indices;
uint32_t *numa_node_ids;
int numa_id;
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.linux.c
int index;
} nfn_linux_fill_cpu_context;
@@ -118,14 +127,43 @@ static int nfn_linux_track_max_id(int value, void *context)
return 1;
}
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.linux.c
static int nfn_linux_fill_cpu_id(int value, void *context)
{
nfn_linux_fill_cpu_context *fill_context = (nfn_linux_fill_cpu_context *)context;
=======
static int nif_linux_read_socket_id(int cpu_id, uint32_t *socket_id)
{
char path[160];
char buffer[64];
char *end = NULL;
long parsed_value;
snprintf(path, sizeof(path),
"/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu_id);
if (!nif_linux_read_first_line(path, buffer, sizeof(buffer)))
return 0;
if (fill_context->internal != NULL)
fill_context->internal[fill_context->index] = (uint64_t)fill_context->index;
if (fill_context->global != NULL)
fill_context->global[fill_context->index] = (uint32_t)value;
errno = 0;
parsed_value = strtol(buffer, &end, 10);
if (end == buffer || errno == ERANGE || parsed_value < 0 || parsed_value > UINT32_MAX)
return 0;
*socket_id = (uint32_t)parsed_value;
return 1;
}
static int nif_linux_fill_cpu_id(int value, void *context)
{
nif_linux_fill_cpu_context *fill_context = (nif_linux_fill_cpu_context *)context;
uint32_t socket_id = 0;
if (!nif_linux_read_socket_id(value, &socket_id))
return 0;
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.linux.c
fill_context->processor_group_ids[fill_context->index] = 0u;
fill_context->socket_ids[fill_context->index] = socket_id;
fill_context->cpu_indices[fill_context->index] = (uint32_t)value;
fill_context->numa_node_ids[fill_context->index] = (uint32_t)fill_context->numa_id;
fill_context->index++;
return 1;
@@ -211,12 +249,21 @@ static int nfn_linux_populate_writable_mapping(void *address, size_t size)
#endif
}
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.linux.c
/* Pin the calling thread to a single logical processor.
* core_id >= 0 : bind to that logical processor (global index, across groups).
* core_id < 0 : clear affinity constraint within the current group. */
NFN_API void NFN_DECL nfn_set_thread_affinity(int core_id, int numa_id)
=======
/* Linux has no Windows-style processor groups; processor_group_id is ignored. */
NIF_API void NIF_DECL nif_set_thread_affinity(int cpu_index, int processor_group_id)
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.linux.c
{
int cpu_count = (int)sysconf(_SC_NPROCESSORS_ONLN);
(void)processor_group_id;
int cpu_count = (int)sysconf(_SC_NPROCESSORS_CONF);
if (cpu_index >= cpu_count)
cpu_count = cpu_index + 1;
if (cpu_count <= 0)
return;
@@ -227,11 +274,11 @@ NFN_API void NFN_DECL nfn_set_thread_affinity(int core_id, int numa_id)
CPU_ZERO_S(size, set);
if (core_id < 0) {
if (cpu_index < 0) {
for (int i = 0; i < cpu_count; i++)
CPU_SET_S((int)i, size, set);
} else {
CPU_SET_S(core_id, size, set);
CPU_SET_S(cpu_index, size, set);
}
pthread_setaffinity_np(pthread_self(), size, set);
@@ -264,9 +311,18 @@ NFN_API int NFN_DECL nfn_get_numa_overall(int *out_numa_count, int *count_of_eac
return 1;
}
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.linux.c
NFN_API int NFN_DECL nfn_get_numa_each(int numa_id, uint64_t *internal, uint32_t *global)
=======
NIF_API int NIF_DECL nif_get_numa_each(int numa_id,
uint32_t *processor_group_ids,
uint32_t *socket_ids,
uint32_t *cpu_indices,
uint32_t *numa_node_ids)
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.linux.c
{
if (numa_id < 0)
if (numa_id < 0 || processor_group_ids == NULL || socket_ids == NULL ||
cpu_indices == NULL || numa_node_ids == NULL)
return 0;
char path[128];
@@ -275,8 +331,20 @@ NFN_API int NFN_DECL nfn_get_numa_each(int numa_id, uint64_t *internal, uint32_t
if (!nfn_linux_read_first_line(path, buffer, sizeof(buffer)))
return 0;
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.linux.c
nfn_linux_fill_cpu_context fill_context = { internal, global, 0 };
return nfn_linux_visit_id_list(buffer, nfn_linux_fill_cpu_id, &fill_context);
=======
nif_linux_fill_cpu_context fill_context = {
processor_group_ids,
socket_ids,
cpu_indices,
numa_node_ids,
numa_id,
0
};
return nif_linux_visit_id_list(buffer, nif_linux_fill_cpu_id, &fill_context);
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.linux.c
}
NFN_API void *NFN_DECL nfn_numa_alloc(size_t size, int numa_id)
+141 -31
View File
@@ -3,33 +3,109 @@
#if NFN_IS_OS(NFN_OS_WINDOWS)
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.windows.c
/* Pin the calling thread to a single logical processor.
* core_id >= 0 : bind to that logical processor (global index, across groups).
* core_id < 0 : clear affinity constraint within the current group. */
NFN_API void NFN_DECL nfn_set_thread_affinity(int core_id, int numa_id)
=======
static int nif_windows_get_socket_map(uint32_t **out_socket_map, DWORD *out_group_count)
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.windows.c
{
if (core_id < 0 || numa_id < 0) {
/* Query which group the thread currently belongs to */
DWORD group_count = GetActiveProcessorGroupCount();
DWORD buffer_size = 0;
uint32_t *socket_map;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *information;
BYTE *cursor;
uint32_t socket_id = 0;
if (group_count == 0)
return 0;
socket_map = (uint32_t *)malloc((size_t)group_count * 64u * sizeof(uint32_t));
if (socket_map == NULL)
return 0;
for (size_t i = 0; i < (size_t)group_count * 64u; i++)
socket_map[i] = UINT32_MAX;
GetLogicalProcessorInformationEx(RelationProcessorPackage, NULL, &buffer_size);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || buffer_size == 0) {
free(socket_map);
return 0;
}
information = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)malloc(buffer_size);
if (information == NULL ||
!GetLogicalProcessorInformationEx(RelationProcessorPackage, information, &buffer_size)) {
free(information);
free(socket_map);
return 0;
}
cursor = (BYTE *)information;
while (cursor < (BYTE *)information + buffer_size) {
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *entry =
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)cursor;
if (entry->Relationship == RelationProcessorPackage) {
PROCESSOR_RELATIONSHIP *package = &entry->Processor;
for (WORD i = 0; i < package->GroupCount; i++) {
WORD group = package->GroupMask[i].Group;
KAFFINITY mask = package->GroupMask[i].Mask;
if (group >= group_count)
continue;
for (DWORD cpu = 0; cpu < 64; cpu++) {
if ((mask & ((KAFFINITY)1 << cpu)) != 0)
socket_map[(size_t)group * 64u + cpu] = socket_id;
}
}
socket_id++;
}
if (entry->Size == 0)
break;
cursor += entry->Size;
}
free(information);
*out_socket_map = socket_map;
*out_group_count = group_count;
return 1;
}
static int nif_windows_get_processor_node(WORD group, BYTE cpu, USHORT *node_id)
{
PROCESSOR_NUMBER processor;
memset(&processor, 0, sizeof(processor));
processor.Group = group;
processor.Number = cpu;
return GetNumaProcessorNodeEx(&processor, node_id) != 0;
}
/* Pin the calling thread using its processor group and group-local CPU index. */
NIF_API void NIF_DECL nif_set_thread_affinity(int cpu_index, int processor_group_id)
{
if (cpu_index < 0 || processor_group_id < 0) {
GROUP_AFFINITY current;
GetThreadGroupAffinity(GetCurrentThread(), &current);
/* Build a full mask for that group's actual core count */
DWORD count = GetActiveProcessorCount(current.Group);
GROUP_AFFINITY ga;
memset(&ga, 0, sizeof(ga));
ga.Group = current.Group;
ga.Mask = (count >= 64) ? ~(KAFFINITY)0 : ((KAFFINITY)1 << count) - 1;
SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL);
GROUP_AFFINITY affinity;
memset(&affinity, 0, sizeof(affinity));
affinity.Group = current.Group;
affinity.Mask = (count >= 64) ? ~(KAFFINITY)0 : ((KAFFINITY)1 << count) - 1;
SetThreadGroupAffinity(GetCurrentThread(), &affinity, NULL);
return;
}
int index = core_id % 64;
DWORD count = GetActiveProcessorCount(numa_id);
if ((DWORD)index >= count)
if ((DWORD)processor_group_id >= GetActiveProcessorGroupCount() || cpu_index >= 64)
return;
GROUP_AFFINITY ga;
memset(&ga, 0, sizeof(ga));
ga.Group = (WORD)numa_id;
ga.Mask = (KAFFINITY)1 << index;
SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL);
USHORT node_id = 0;
if (!nif_windows_get_processor_node((WORD)processor_group_id, (BYTE)cpu_index, &node_id))
return;
GROUP_AFFINITY affinity;
memset(&affinity, 0, sizeof(affinity));
affinity.Group = (WORD)processor_group_id;
affinity.Mask = (KAFFINITY)1 << cpu_index;
SetThreadGroupAffinity(GetCurrentThread(), &affinity, NULL);
}
NFN_API int NFN_DECL nfn_get_numa_overall(int *out_numa_count, int *count_of_each_numa)
@@ -39,30 +115,64 @@ NFN_API int NFN_DECL nfn_get_numa_overall(int *out_numa_count, int *count_of_eac
return 0;
*out_numa_count = (int)highest + 1;
for (UCHAR n = 0; n <= (UCHAR)highest; n++) {
ULONGLONG mask = 0;
GetNumaNodeProcessorMask(n, &mask);
count_of_each_numa[n] = (int)__popcnt64(mask);
if (count_of_each_numa != NULL) {
for (ULONG n = 0; n <= highest; n++)
count_of_each_numa[n] = 0;
}
DWORD group_count = GetActiveProcessorGroupCount();
for (DWORD group = 0; group < group_count; group++) {
for (DWORD cpu = 0; cpu < 64; cpu++) {
USHORT node_id = 0;
if (nif_windows_get_processor_node((WORD)group, (BYTE)cpu, &node_id) &&
count_of_each_numa != NULL && node_id <= highest)
count_of_each_numa[node_id]++;
}
}
return 1;
}
<<<<<<< HEAD:src/Nitload.Native/nfn-src/thread.windows.c
NFN_API int NFN_DECL nfn_get_numa_each(int numa_id, uint64_t *internal, uint32_t *global)
=======
NIF_API int NIF_DECL nif_get_numa_each(int numa_id,
uint32_t *processor_group_ids,
uint32_t *socket_ids,
uint32_t *cpu_indices,
uint32_t *numa_node_ids)
>>>>>>> 3a2b1234782f893f5b71655289b372ffed8dfd93:src/Nitload.Native/nif-src/thread.windows.c
{
ULONGLONG mask = 0;
if (!GetNumaNodeProcessorMask((UCHAR)numa_id, &mask))
if (numa_id < 0 || processor_group_ids == NULL || socket_ids == NULL ||
cpu_indices == NULL || numa_node_ids == NULL)
return 0;
int intra = 0;
while (mask) {
DWORD idx;
_BitScanForward64(&idx, mask);
if (internal != NULL)
internal[intra] = (uint64_t)intra;
global[intra] = (uint32_t)idx;
intra++;
mask &= mask - 1;
uint32_t *socket_map = NULL;
DWORD group_count = 0;
if (!nif_windows_get_socket_map(&socket_map, &group_count))
return 0;
int index = 0;
for (DWORD group = 0; group < group_count; group++) {
for (DWORD cpu = 0; cpu < 64; cpu++) {
USHORT node_id = 0;
if (!nif_windows_get_processor_node((WORD)group, (BYTE)cpu, &node_id) ||
node_id != (USHORT)numa_id)
continue;
uint32_t socket_id = socket_map[(size_t)group * 64u + cpu];
if (socket_id == UINT32_MAX) {
free(socket_map);
return 0;
}
processor_group_ids[index] = (uint32_t)group;
socket_ids[index] = socket_id;
cpu_indices[index] = cpu;
numa_node_ids[index] = node_id;
index++;
}
}
free(socket_map);
return 1;
}
@@ -0,0 +1,39 @@
#ifndef NIF_NATIVE_H
#define NIF_NATIVE_H
#ifdef __cplusplus
#error "This header is not meant to be included in C++ code. Nitload.Native is a C library and should be used with C linkage."
#endif
#include "nif_internal.h"
#include "nif_target.h"
#include <immintrin.h>
#include <assert.h>
#include <glfw_function.h>
#define byte char
#define cs_char uint16_t
#define nif_null_assert(ptr) assert(ptr != NULL)
#ifndef NIF_
#endif
NIF_API void NIF_DECL nif_load_glfw_functions(GLFWFunctionTable *table);
NIF_API void NIF_DECL nif_load_intrinsic_function(void *intrinsic_context, uint64_t id);
NIF_API SIMDID NIF_DECL nif_get_simd_level_global();
/* Per-core variant: always re-executes CPUID, never caches.
* Must be called on the target core (after affinity is set). */
NIF_API SIMDID NIF_DECL nif_get_simd_level_local();
NIF_API SIMDID NIF_DECL nif_get_unite_simd(SIMDID left, SIMDID right);
NIF_API int NIF_DECL nif_compare_simd(SIMDID left, SIMDID right);
NIF_API void NIF_DECL nif_set_thread_affinity(int cpu_index, int processor_group_id);
NIF_API void* NIF_DECL nif_numa_alloc(size_t size, int numa_id);
NIF_API void NIF_DECL nif_numa_free(void *ptr, size_t size, int numa_id);
NIF_API int NIF_DECL nif_get_numa_each(int numa_id,
uint32_t *processor_group_ids,
uint32_t *socket_ids,
uint32_t *cpu_indices,
uint32_t *numa_node_ids);
NIF_API int NIF_DECL nif_get_numa_overall(int *out_numa_count, int *count_of_each_numa);
#endif