Skip to content

Commit

Permalink
Added NIC discovery and the ability to bind by numa node rather than …
Browse files Browse the repository at this point in the history
…cpu. Also numa discovery works on windows.
  • Loading branch information
JonathanHenson committed Oct 31, 2023
1 parent 1019baa commit 6015154
Show file tree
Hide file tree
Showing 7 changed files with 495 additions and 42 deletions.
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
cmake_minimum_required(VERSION 3.0)
option(ALLOW_CROSS_COMPILED_TESTS "Allow tests to be compiled via cross compile, for use with qemu" OFF)

if (WIN32)
# needed for COM interop */
project(aws-c-common LANGUAGES C CXX VERSION 0.1.0)
else()
project(aws-c-common LANGUAGES C VERSION 0.1.0)
endif()

message(STATUS "CMake ${CMAKE_VERSION}")

Expand Down Expand Up @@ -70,7 +75,7 @@ if (WIN32)

file(GLOB AWS_COMMON_OS_SRC
"source/windows/*.c"
"source/platform_fallback_stubs/system_info.c"
"source/windows/*.cpp"
)

if (MSVC)
Expand All @@ -82,7 +87,7 @@ if (WIN32)
endif ()

list(APPEND PLATFORM_DEFINES WINDOWS_KERNEL_LIB=${WINDOWS_KERNEL_LIB})
list(APPEND PLATFORM_LIBS BCrypt ${WINDOWS_KERNEL_LIB} Ws2_32 Shlwapi)
list(APPEND PLATFORM_LIBS BCrypt ${WINDOWS_KERNEL_LIB} Ws2_32 Shlwapi wbemuuid)
else ()
file(GLOB AWS_COMMON_OS_HEADERS
"include/aws/common/posix/*"
Expand Down
12 changes: 12 additions & 0 deletions include/aws/common/byte_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ AWS_COMMON_API int aws_byte_buf_init_copy(
struct aws_allocator *allocator,
const struct aws_byte_buf *src);


/**
* Initializes an aws_byte_buf structure base from orignal, while also replacing
* replacement_pattern found in original with replace_with.
*/
int aws_byte_buf_init_and_replace(
struct aws_byte_buf *buf,
struct aws_allocator *allocator,
struct aws_byte_cursor original,
struct aws_byte_cursor replacement_pattern,
struct aws_byte_cursor replace_with);

/**
* Reads 'filename' into 'out_buf'. If successful, 'out_buf' is allocated and filled with the data;
* It is your responsibility to call 'aws_byte_buf_clean_up()' on it. Otherwise, 'out_buf' remains
Expand Down
7 changes: 4 additions & 3 deletions include/aws/common/private/system_info_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,19 @@ struct aws_system_environment {
void *impl;
};

AWS_EXTERN_C_BEGIN
/**
* For internal implementors. Fill in info in env that you're able to grab, such as dmi info, os version strings etc...
* in here. The default just returns AWS_OP_SUCCESS. This is currently only implemented for linux.
*
* Returns AWS_OP_ERR if the implementation wasn't able to fill in required information for the platform.
*/
int aws_system_environment_load_platform_impl(struct aws_system_environment *env);
AWS_COMMON_API int aws_system_environment_load_platform_impl(struct aws_system_environment *env);

/**
* For internal implementors. Cleans up anything allocated in aws_system_environment_load_platform_impl,
* but does not release the memory for env.
*/
void aws_system_environment_destroy_platform_impl(struct aws_system_environment *env);

AWS_COMMON_API void aws_system_environment_destroy_platform_impl(struct aws_system_environment *env);
AWS_EXTERN_C_END
#endif // AWS_COMMON_PRIVATE_SYSTEM_INFO_PRIV_H
65 changes: 65 additions & 0 deletions source/byte_buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,71 @@ int aws_byte_cursor_split_on_char_n(
return AWS_OP_SUCCESS;
}

int aws_byte_buf_init_and_replace(
struct aws_byte_buf* buf,
struct aws_allocator *allocator,
struct aws_byte_cursor original,
struct aws_byte_cursor replacement_pattern,
struct aws_byte_cursor replace_with) {
if (!allocator || !buf) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}

if (replacement_pattern.len == 0) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}

size_t num_occurrences = 0;
struct aws_byte_cursor search_cursor = original;
while (search_cursor.len > 0) {
struct aws_byte_cursor result;
if (aws_byte_cursor_find_exact(&search_cursor, &replacement_pattern, &result) == AWS_OP_SUCCESS) {
num_occurrences++;
aws_byte_cursor_advance(&search_cursor, (result.ptr - search_cursor.ptr) + replacement_pattern.len);
} else {
break;
}
}

size_t new_len = original.len - (num_occurrences * replacement_pattern.len) + (num_occurrences * replace_with.len);
if (aws_byte_buf_init(buf, allocator, new_len)) {
return AWS_OP_ERR;
}

search_cursor = original;
while (search_cursor.len > 0) {
struct aws_byte_cursor result;
if (aws_byte_cursor_find_exact(&search_cursor, &replacement_pattern, &result) == AWS_OP_SUCCESS) {
/* Copy everything before the found pattern */
if (result.ptr != search_cursor.ptr) {
struct aws_byte_cursor prefix =
aws_byte_cursor_from_array(search_cursor.ptr, result.ptr - search_cursor.ptr);
if (aws_byte_buf_append(buf, &prefix)) {
aws_byte_buf_clean_up(buf);
return AWS_OP_ERR;
}
}
/* Copy the replacement string */
if (aws_byte_buf_append(buf, &replace_with)) {
aws_byte_buf_clean_up(buf);
return AWS_OP_ERR;
}
/* Move the search cursor */
size_t skip_len = (result.ptr - search_cursor.ptr) + replacement_pattern.len;
aws_byte_cursor_advance(&search_cursor, skip_len);
} else {
/* Copy the remaining part of the string, as no more patterns are found */
if (aws_byte_buf_append(buf, &search_cursor)) {
aws_byte_buf_clean_up(buf);
return AWS_OP_ERR;
}
break;
}
}

return AWS_OP_SUCCESS;
}

int aws_byte_cursor_split_on_char(
const struct aws_byte_cursor *AWS_RESTRICT input_str,
char split_on,
Expand Down
142 changes: 131 additions & 11 deletions source/windows/system_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

#include <aws/common/system_info.h>
#include <aws/common/private/system_info_priv.h>

#include <aws/common/byte_buf.h>
#include <aws/common/logging.h>
#include <aws/common/thread.h>

#include <windows.h>
#include <Windows.h>

enum aws_platform_os aws_get_platform_build_os(void) {
return AWS_PLATFORM_OS_WINDOWS;
Expand All @@ -21,31 +20,152 @@ size_t aws_system_info_processor_count(void) {
return info.dwNumberOfProcessors;
}

/* the next three functions need actual implementations before we can have proper numa alignment on windows.
* For now leave them stubbed out. */

#if defined(AWS_OS_WINDOWS_DESKTOP)
/* Convert a string from a macro to a wide string */
# define WIDEN2(s) L## # s
# define WIDEN(s) WIDEN2(s)

static aws_thread_once s_check_active_processor_functions_once = INIT_ONCE_STATIC_INIT;

typedef BOOL WINAPI GetLogicalProcessorInformationEx_fn(
LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType,
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX Buffer,
PDWORD ReturnedLength);
static GetLogicalProcessorInformationEx_fn *s_GetLogicalProcessorInformationEx;


static void s_check_active_processor_functions(void *user_data) {
(void)user_data;

s_GetLogicalProcessorInformationEx =
(GetLogicalProcessorInformationEx_fn *)GetProcAddress(GetModuleHandleW(WIDEN(WINDOWS_KERNEL_LIB) L".dll"),
"GetLogicalProcessorInformationEx");

}
#endif

uint16_t aws_get_cpu_group_count(void) {
return 1U;
#if defined(AWS_OS_WINDOWS_DESKTOP)
/* Check for functions that don't exist on ancient Windows */
aws_thread_call_once(&s_check_active_processor_functions_once, s_check_active_processor_functions, NULL);
AWS_FATAL_ASSERT(s_GetLogicalProcessorInformationEx);

ULONG buffer_length = 0;
s_GetLogicalProcessorInformationEx(RelationNumaNode, NULL, &buffer_length);
AWS_FATAL_ASSERT(buffer_length);

struct aws_allocator *allocator = aws_default_allocator();
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX buffer =
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)aws_mem_acquire(allocator, buffer_length);
AWS_FATAL_ASSERT(s_GetLogicalProcessorInformationEx(RelationNumaNode, buffer, &buffer_length));

uint16_t count = 0;
ULONG offset = 0;
while (offset < buffer_length) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info =
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((uint8_t *)buffer + offset);
if (info->Relationship == RelationNumaNode) {
count++;
}
offset += info->Size;
}

aws_mem_release(allocator, buffer);
return count;
#else
return 1L;
#endif /* defined(AWS_OS_WINDOWS_DESKTOP) */
}

static size_t s_count_set_bits(ULONGLONG number) {
size_t count = 0;
while (number) {
count += number & 1;
number >>= 1;
}
return count;
}

size_t aws_get_cpu_count_for_group(uint16_t group_idx) {
(void)group_idx;
return aws_system_info_processor_count();

#if defined(AWS_OS_WINDOWS_DESKTOP)
aws_thread_call_once(&s_check_active_processor_functions_once, s_check_active_processor_functions, NULL);
AWS_FATAL_ASSERT(s_GetLogicalProcessorInformationEx);
ULONG buffer_length = 0;
s_GetLogicalProcessorInformationEx(RelationNumaNode, NULL, &buffer_length);
AWS_FATAL_ASSERT(buffer_length);

struct aws_allocator *allocator = aws_default_allocator();
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX buffer =
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)aws_mem_acquire(allocator, buffer_length);
AWS_FATAL_ASSERT(s_GetLogicalProcessorInformationEx(RelationNumaNode, buffer, &buffer_length));

size_t cpu_count = 0;
ULONG offset = 0;
while (offset < buffer_length) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info =
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((uint8_t *)buffer + offset);
if (info->Relationship == RelationNumaNode && info->NumaNode.NodeNumber == group_idx) {
cpu_count = s_count_set_bits(info->NumaNode.GroupMask.Mask);
break;
}
offset += info->Size;
}

aws_mem_release(allocator, buffer);
return cpu_count;
#else
return group_idx == 0 ? aws_system_info_processor_count() : 0;
#endif /* defined(AWS_OS_WINDOWS_DESKTOP) */

}

void aws_get_cpu_ids_for_group(uint16_t group_idx, struct aws_cpu_info *cpu_ids_array, size_t cpu_ids_array_length) {
(void)group_idx;
#if defined(AWS_OS_WINDOWS_DESKTOP)
/* Check for functions that don't exist on ancient Windows */
aws_thread_call_once(&s_check_active_processor_functions_once, s_check_active_processor_functions, NULL);
AWS_FATAL_ASSERT(s_GetLogicalProcessorInformationEx);

if (!cpu_ids_array_length) {
return;
ULONG buffer_length = 0;
s_GetLogicalProcessorInformationEx(RelationNumaNode, NULL, &buffer_length);
AWS_FATAL_ASSERT(buffer_length);

struct aws_allocator *allocator = aws_default_allocator();
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX buffer =
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)aws_mem_acquire(allocator, buffer_length);
AWS_FATAL_ASSERT(s_GetLogicalProcessorInformationEx(RelationNumaNode, buffer, &buffer_length));

size_t cpu_count = 0;
ULONG offset = 0;
size_t hyper_threads_hint = cpu_ids_array_length / 2 - 1;

while (offset < buffer_length) {
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info =
(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)((uint8_t *)buffer + offset);
if (info->Relationship == RelationNumaNode && info->NumaNode.NodeNumber == group_idx) {
ULONGLONG mask = info->NumaNode.GroupMask.Mask;
for (size_t i = 0; i < cpu_ids_array_length; i++) {
if (mask & ((ULONGLONG)1 << i)) {
cpu_ids_array[i].cpu_id = (int32_t)i;
cpu_ids_array[i].suspected_hyper_thread = i > hyper_threads_hint;
}
}
break;
}
offset += info->Size;
}

aws_mem_release(allocator, buffer);
#else
/* a crude hint, but hyper-threads are numbered as the second half of the cpu id listing. */
size_t hyper_threads_hint = cpu_ids_array_length / 2 - 1;

for (size_t i = 0; i < cpu_ids_array_length; ++i) {
cpu_ids_array[i].cpu_id = (int32_t)i;
cpu_ids_array[i].suspected_hyper_thread = i > hyper_threads_hint;
}
#endif /* defined(AWS_OS_WINDOWS_DESKTOP) */
}

bool aws_is_debugger_present(void) {
Expand Down
Loading

0 comments on commit 6015154

Please sign in to comment.