Skip to content

Commit

Permalink
Add an environment loader API and implementation for some DMI related…
Browse files Browse the repository at this point in the history
… fields (#1063)

Co-authored-by: Michael Graeb <[email protected]>
  • Loading branch information
JonathanHenson and graebm authored Oct 17, 2023
1 parent 0baed28 commit b61c12e
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 0 deletions.
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ if (WIN32)

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

if (MSVC)
Expand Down Expand Up @@ -108,19 +109,26 @@ else ()
# Don't add the exact path to CoreFoundation as this would hardcode the SDK version
list(APPEND PLATFORM_LIBS dl Threads::Threads "-framework CoreFoundation")
list (APPEND AWS_COMMON_OS_SRC "source/darwin/*.c") # OS specific includes
list (APPEND AWS_COMMON_OS_SRC "source/platform_fallback_stubs/system_info.c")
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") # Android does not link to libpthread nor librt, so this is fine
list(APPEND PLATFORM_LIBS dl m Threads::Threads rt)
list (APPEND AWS_COMMON_OS_SRC "source/linux/*.c") # OS specific includes
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
list(APPEND PLATFORM_LIBS dl m thr execinfo)
list (APPEND AWS_COMMON_OS_SRC "source/platform_fallback_stubs/system_info.c")
elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
list(APPEND PLATFORM_LIBS dl m Threads::Threads execinfo)
list (APPEND AWS_COMMON_OS_SRC "source/platform_fallback_stubs/system_info.c")
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
list(APPEND PLATFORM_LIBS m Threads::Threads execinfo)
list (APPEND AWS_COMMON_OS_SRC "source/platform_fallback_stubs/system_info.c")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
list(APPEND PLATFORM_LIBS log)
file(GLOB ANDROID_SRC "source/android/*.c")
list(APPEND AWS_COMMON_OS_SRC "${ANDROID_SRC}")
list (APPEND AWS_COMMON_OS_SRC "source/platform_fallback_stubs/system_info.c")
else()
list (APPEND AWS_COMMON_OS_SRC "source/platform_fallback_stubs/system_info.c")
endif()

endif()
Expand Down Expand Up @@ -298,6 +306,7 @@ configure_file(${CONFIG_HEADER_TEMPLATE}
if (ALLOW_CROSS_COMPILED_TESTS OR NOT CMAKE_CROSSCOMPILING)
if (BUILD_TESTING)
add_subdirectory(tests)
add_subdirectory(bin/system_info)
endif()
endif()

Expand Down
18 changes: 18 additions & 0 deletions bin/system_info/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
project(print-sys-info C)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/lib/cmake")

file(GLOB SI_SRC
"*.c"
)

set(SI_PROJECT_NAME print-sys-info)
add_executable(${SI_PROJECT_NAME} ${SI_SRC})
aws_set_common_properties(${SI_PROJECT_NAME})


target_include_directories(${SI_PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)

target_link_libraries(${SI_PROJECT_NAME} PRIVATE aws-c-common)
48 changes: 48 additions & 0 deletions bin/system_info/print_system_info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@


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

int main(void) {
struct aws_allocator *allocator = aws_default_allocator();
aws_common_library_init(allocator);
struct aws_logger_standard_options options = {
.file = stderr,
.level = AWS_LOG_LEVEL_TRACE,
};

struct aws_logger logger;
aws_logger_init_standard(&logger, allocator, &options);
aws_logger_set(&logger);

struct aws_system_environment *env = aws_system_environment_load(allocator);

fprintf(stdout, "crt-detected env: {\n");

struct aws_byte_cursor virtualization_vendor = aws_system_environment_get_virtualization_vendor(env);
fprintf(
stdout,
" 'virtualization vendor': '" PRInSTR "',\n",
(int)virtualization_vendor.len,
virtualization_vendor.ptr);
struct aws_byte_cursor product_name = aws_system_environment_get_virtualization_product_name(env);
fprintf(stdout, " 'product name': '" PRInSTR "',\n", (int)product_name.len, product_name.ptr);
fprintf(
stdout, " 'number of processors': '%lu',\n", (unsigned long)aws_system_environment_get_processor_count(env));
size_t numa_nodes = aws_system_environment_get_cpu_group_count(env);

if (numa_nodes > 1) {
fprintf(stdout, " 'numa architecture': 'true',\n");
fprintf(stdout, " 'number of numa nodes': '%lu'\n", (unsigned long)numa_nodes);
} else {
fprintf(stdout, " 'numa architecture': 'false'\n");
}

fprintf(stdout, "}\n");
aws_system_environment_release(env);
aws_logger_clean_up(&logger);

aws_common_library_clean_up();
return 0;
}
37 changes: 37 additions & 0 deletions include/aws/common/private/system_info_priv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef AWS_COMMON_PRIVATE_SYSTEM_INFO_PRIV_H
#define AWS_COMMON_PRIVATE_SYSTEM_INFO_PRIV_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/byte_buf.h>
#include <aws/common/ref_count.h>
#include <aws/common/string.h>
#include <aws/common/system_info.h>

struct aws_system_environment {
struct aws_allocator *allocator;
struct aws_ref_count ref_count;
struct aws_byte_buf virtualization_vendor;
struct aws_byte_buf product_name;
enum aws_platform_os os;
size_t cpu_count;
size_t cpu_group_count;
void *impl;
};

/**
* 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);

/**
* 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);

#endif // AWS_COMMON_PRIVATE_SYSTEM_INFO_PRIV_H
47 changes: 47 additions & 0 deletions include/aws/common/system_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* SPDX-License-Identifier: Apache-2.0.
*/

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

AWS_PUSH_SANE_WARNING_LEVEL
Expand All @@ -21,8 +22,54 @@ struct aws_cpu_info {
bool suspected_hyper_thread;
};

struct aws_system_environment;

AWS_EXTERN_C_BEGIN

/**
* Allocates and initializes information about the system the current process is executing on.
* If successful returns an instance of aws_system_environment. If it fails, it will return NULL.
*
* Note: This api is used internally and is still early in its evolution.
* It may change in incompatible ways in the future.
*/
AWS_COMMON_API
struct aws_system_environment *aws_system_environment_load(struct aws_allocator *allocator);

AWS_COMMON_API
struct aws_system_environment *aws_system_environment_acquire(struct aws_system_environment *env);

AWS_COMMON_API
void aws_system_environment_release(struct aws_system_environment *env);

/**
* Returns the virtualization vendor for the specified compute environment, e.g. "Xen, Amazon EC2, etc..."
*
* The return value may be empty and in that case no vendor was detected.
*/
AWS_COMMON_API
struct aws_byte_cursor aws_system_environment_get_virtualization_vendor(const struct aws_system_environment *env);

/**
* Returns the product name for the specified compute environment. For example, the Amazon EC2 Instance type.
*
* The return value may be empty and in that case no vendor was detected.
*/
AWS_COMMON_API
struct aws_byte_cursor aws_system_environment_get_virtualization_product_name(const struct aws_system_environment *env);

/**
* Returns the number of processors for the specified compute environment.
*/
AWS_COMMON_API
size_t aws_system_environment_get_processor_count(struct aws_system_environment *env);

/**
* Returns the number of separate cpu groupings (multi-socket configurations or NUMA).
*/
AWS_COMMON_API
size_t aws_system_environment_get_cpu_group_count(const struct aws_system_environment *env);

/* Returns the OS this was built under */
AWS_COMMON_API
enum aws_platform_os aws_get_platform_build_os(void);
Expand Down
24 changes: 24 additions & 0 deletions source/linux/system_info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/file.h>
#include <aws/common/private/system_info_priv.h>

int aws_system_environment_load_platform_impl(struct aws_system_environment *env) {
/* provide size_hint when reading "special files", since some platforms mis-report these files' size as 4KB */
aws_byte_buf_init_from_file_with_size_hint(
&env->virtualization_vendor, env->allocator, "/sys/devices/virtual/dmi/id/sys_vendor", 32 /*size_hint*/);

/* whether this one works depends on if this is a sysfs filesystem. If it fails, it will just be empty
* and these APIs are a best effort at the moment. We can add fallbacks as the loaders get more complicated. */
aws_byte_buf_init_from_file_with_size_hint(
&env->product_name, env->allocator, "/sys/devices/virtual/dmi/id/product_name", 32 /*size_hint*/);

return AWS_OP_SUCCESS;
}

void aws_system_environment_destroy_platform_impl(struct aws_system_environment *env) {
aws_byte_buf_clean_up(&env->virtualization_vendor);
aws_byte_buf_clean_up(&env->product_name);
}
21 changes: 21 additions & 0 deletions source/platform_fallback_stubs/system_info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/private/system_info_priv.h>

#include <aws/common/logging.h>

int aws_system_environment_load_platform_impl(struct aws_system_environment *env) {
(void)env;
AWS_LOGF_DEBUG(
AWS_LS_COMMON_GENERAL,
"id=%p: platform specific environment loading is not implemented for this platform.",
(void *)env);

return AWS_OP_SUCCESS;
}

void aws_system_environment_destroy_platform_impl(struct aws_system_environment *env) {
(void)env;
}
80 changes: 80 additions & 0 deletions source/system_info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/private/system_info_priv.h>

#include <aws/common/logging.h>

void s_destroy_env(void *arg) {
struct aws_system_environment *env = arg;

if (env) {
aws_system_environment_destroy_platform_impl(env);
aws_mem_release(env->allocator, env);
}
}

struct aws_system_environment *aws_system_environment_load(struct aws_allocator *allocator) {
struct aws_system_environment *env = aws_mem_calloc(allocator, 1, sizeof(struct aws_system_environment));
env->allocator = allocator;
aws_ref_count_init(&env->ref_count, env, s_destroy_env);

if (aws_system_environment_load_platform_impl(env)) {
AWS_LOGF_ERROR(
AWS_LS_COMMON_GENERAL,
"id=%p: failed to load system environment with error %s.",
(void *)env,
aws_error_debug_str(aws_last_error()));
goto error;
}

AWS_LOGF_TRACE(
AWS_LS_COMMON_GENERAL,
"id=%p: virtualization vendor detected as \"" PRInSTR "\"",
(void *)env,
AWS_BYTE_CURSOR_PRI(aws_system_environment_get_virtualization_vendor(env)));
AWS_LOGF_TRACE(
AWS_LS_COMMON_GENERAL,
"id=%p: virtualization product name detected as \"" PRInSTR " \"",
(void *)env,
AWS_BYTE_CURSOR_PRI(aws_system_environment_get_virtualization_vendor(env)));

env->os = aws_get_platform_build_os();
env->cpu_count = aws_system_info_processor_count();
env->cpu_group_count = aws_get_cpu_group_count();

return env;
error:
s_destroy_env(env);
return NULL;
}

struct aws_system_environment *aws_system_environment_acquire(struct aws_system_environment *env) {
aws_ref_count_acquire(&env->ref_count);
return env;
}

void aws_system_environment_release(struct aws_system_environment *env) {
aws_ref_count_release(&env->ref_count);
}

struct aws_byte_cursor aws_system_environment_get_virtualization_vendor(const struct aws_system_environment *env) {
struct aws_byte_cursor vendor_string = aws_byte_cursor_from_buf(&env->virtualization_vendor);
return aws_byte_cursor_trim_pred(&vendor_string, aws_char_is_space);
}

struct aws_byte_cursor aws_system_environment_get_virtualization_product_name(
const struct aws_system_environment *env) {
struct aws_byte_cursor product_name_str = aws_byte_cursor_from_buf(&env->product_name);
return aws_byte_cursor_trim_pred(&product_name_str, aws_char_is_space);
}

size_t aws_system_environment_get_processor_count(struct aws_system_environment *env) {
return env->cpu_count;
}

AWS_COMMON_API
size_t aws_system_environment_get_cpu_group_count(const struct aws_system_environment *env) {
return env->cpu_group_count;
}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ add_test_case(test_cpu_count_at_least_works_superficially)
add_test_case(test_stack_trace_decoding)
add_test_case(test_platform_build_os)
add_test_case(test_sanity_check_numa_discovery)
add_test_case(test_sanity_check_environment_loader)

add_test_case(test_realloc_fallback)
add_test_case(test_realloc_passthrough)
Expand Down
19 changes: 19 additions & 0 deletions tests/system_info_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,22 @@ static int s_test_sanity_check_numa_discovery(struct aws_allocator *allocator, v
}

AWS_TEST_CASE(test_sanity_check_numa_discovery, s_test_sanity_check_numa_discovery)

static int s_test_sanity_check_environment_loader(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

aws_common_library_init(allocator);
struct aws_system_environment *env = aws_system_environment_load(allocator);
ASSERT_NOT_NULL(env);
struct aws_byte_cursor virt_vendor = aws_system_environment_get_virtualization_vendor(env);
ASSERT_TRUE(aws_byte_cursor_is_valid(&virt_vendor));
struct aws_byte_cursor virt_product = aws_system_environment_get_virtualization_product_name(env);
ASSERT_TRUE(aws_byte_cursor_is_valid(&virt_product));

aws_system_environment_release(env);

aws_common_library_clean_up();
return 0;
}

AWS_TEST_CASE(test_sanity_check_environment_loader, s_test_sanity_check_environment_loader)

0 comments on commit b61c12e

Please sign in to comment.