Add sysinfo abstraction (primarily for getting processor count) (#54)

* Rename specs to be suffixed with requirements

* Add header, spec and basic int test for sysinfo

* Add UT project for sysinfo_win32

* Add unit tests for sysinfo_win32

* Add unit tests for Linux also
This commit is contained in:
Dan Cristoloveanu 2020-11-02 19:36:25 -08:00 коммит произвёл GitHub
Родитель 6bb3b0f59f
Коммит b2af7d8449
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 606 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,24 @@
# sysinfo
================
## Overview
`sysinfo` provides platform-independent primitives to obtain system information (like processor count).
## Exposed API
```c
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
```
### sysinfo_get_processor_count
```c
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
```
`sysinfo_get_processor_count` gets the processor count.
**SRS_SYSINFO_01_001: [** `sysinfo_get_processor_count` shall obtain the processor count as reported by the operating system. **]**
**SRS_SYSINFO_01_002: [** If any error occurs, `sysinfo_get_processor_count` shall return 0. **]**

Просмотреть файл

@ -0,0 +1,26 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifndef SYSINFO_H
#define SYSINFO_H
#ifdef __cplusplus
#include <cstdint>
#else
#include <stdint.h>
#endif
#include "umock_c/umock_c_prod.h"
#ifdef __cplusplus
extern "C"
{
#endif
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
#ifdef __cplusplus
}
#endif
#endif /* SYSINFO_H */

Просмотреть файл

@ -4,6 +4,7 @@ if(${run_int_tests})
build_test_folder(interlocked_int)
build_test_folder(timer_int)
build_test_folder(sync_int)
build_test_folder(sysinfo_int)
if(MSVC)
# waiting for timer to be implemented on linux
build_test_folder(file_int)

Просмотреть файл

@ -0,0 +1,14 @@
#Copyright (c) Microsoft. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
set(theseTestsName sysinfo_int)
set(${theseTestsName}_test_files
${theseTestsName}.c
)
set(${theseTestsName}_h_files
../../inc/c_pal/sysinfo.h
)
build_test_artifacts(${theseTestsName} ON "tests/c_pal/int" ADDITIONAL_LIBS c_pal)

Просмотреть файл

@ -0,0 +1,12 @@
//Copyright(c) Microsoft.All rights reserved.
//Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stddef.h>
#include "testrunnerswitcher.h"
int main(void)
{
size_t failedTestCount = 0;
RUN_TEST_SUITE(sysinfo_int, failedTestCount);
return failedTestCount;
}

Просмотреть файл

@ -0,0 +1,65 @@
//Copyright(c) Microsoft.All rights reserved.
//Licensed under the MIT license. See LICENSE file in the project root for full license information.
#ifdef __cplusplus
#include <cstdint>
#else
#include <stdint.h>
#endif
#include "testrunnerswitcher.h"
#include "testrunnerswitcher.h"
#include "c_pal/gballoc_hl.h"
#include "c_pal/gballoc_hl_redirect.h"
#include "c_pal/sysinfo.h"
static TEST_MUTEX_HANDLE g_testByTest;
BEGIN_TEST_SUITE(sysinfo_int)
TEST_SUITE_INITIALIZE(a)
{
ASSERT_ARE_EQUAL(int, 0, gballoc_hl_init(NULL, NULL));
g_testByTest = TEST_MUTEX_CREATE();
ASSERT_IS_NOT_NULL(g_testByTest);
}
TEST_SUITE_CLEANUP(b)
{
TEST_MUTEX_DESTROY(g_testByTest);
gballoc_hl_deinit();
}
TEST_FUNCTION_INITIALIZE(c)
{
if (TEST_MUTEX_ACQUIRE(g_testByTest))
{
ASSERT_FAIL("our mutex is ABANDONED. Failure in test framework");
}
}
TEST_FUNCTION_CLEANUP(d)
{
TEST_MUTEX_RELEASE(g_testByTest);
}
/* sysinfo_get_processor_count */
/* Tests_SRS_SYSINFO_01_001: [ sysinfo_get_processor_count shall obtain the processor count as reported by the operating system. ]*/
TEST_FUNCTION(sysinfo_get_processor_count_returns_processor_count)
{
///arrange
///act
uint32_t proc_count = sysinfo_get_processor_count();
///assert
ASSERT_ARE_NOT_EQUAL(uint32_t, 0, proc_count);
}
/* Tests_SRS_SYSINFO_01_002: [ If any error occurs, `sysinfo_get_processor_count` shall return 0. ]*/
/* Can't really be induced on "any" platform, tested independently for each psupported platform */
END_TEST_SUITE(sysinfo_int)

Просмотреть файл

@ -30,6 +30,7 @@ set(pal_linux_c_files
src/uniqueid_linux.c
src/sync_linux.c
src/string_utils.c
src/sysinfo_linux.c
src/file_linux.c
src/timer_linux.c
src/${gballoc_ll_c}

Просмотреть файл

@ -0,0 +1,26 @@
# sysinfo_linux
================
## Overview
`sysinfo_linux` provides the Linux implementation for `sysinfo`.
## Exposed API
```c
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
```
### sysinfo_get_processor_count
```c
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
```
`sysinfo_get_processor_count` returns the processor count as returned by the operating system.
**SRS_SYSINFO_LINUX_01_001: [** `sysinfo_get_processor_count` shall call `sysconf` with `SC_NPROCESSORS_ONLN` to obtain the number of configured processors. **]**
**SRS_SYSINFO_LINUX_01_002: [** If any error occurs, `sysinfo_get_processor_count` shall return 0. **]**
**SRS_SYSINFO_LINUX_01_003: [** If `sysconf` returns a number bigger than `UINT32_MAX`, `sysinfo_get_processor_count` shall fail and return 0. **]**

38
linux/src/sysinfo_linux.c Normal file
Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
#include <inttypes.h>
#include <unistd.h>
#include "c_logging/xlogging.h"
#include "c_pal/sysinfo.h"
uint32_t sysinfo_get_processor_count(void)
{
/* Codes_SRS_SYSINFO_01_001: [ sysinfo_get_processor_count shall obtain the processor count as reported by the operating system. ]*/
/* Codes_SRS_SYSINFO_LINUX_01_001: [ sysinfo_get_processor_count shall call sysconf with SC_NPROCESSORS_ONLN to obtain the number of configured processors. ]*/
uint32_t result;
long sysconf_result = sysconf(_SC_NPROCESSORS_ONLN);
if (sysconf_result < 0)
{
/* Codes_SRS_SYSINFO_01_002: [ If any error occurs, `sysinfo_get_processor_count` shall return 0. ]*/
/* Codes_SRS_SYSINFO_LINUX_01_002: [ If any error occurs, `sysinfo_get_processor_count` shall return 0. ]*/
LogError("sysconf(_SC_NPROCESSORS_ONLN) failed with %ld", sysconf_result);
result = 0;
}
else
{
/* Codes_SRS_SYSINFO_LINUX_01_003: [ If sysconf returns a number bigger than UINT32_MAX, sysinfo_get_processor_count shall fail and return 0. ]*/
if (sysconf_result > UINT32_MAX)
{
LogError("sysconf(_SC_NPROCESSORS_ONLN) returned %ld, wow that's a lot of processors!", sysconf_result);
result = 0;
}
else
{
result = (uint32_t)sysconf_result;
LogInfo("Detected %" PRIu32 " processors", result);
}
}
return result;
}

Просмотреть файл

@ -6,6 +6,7 @@ if(${run_unittests})
build_test_folder(uniqueid_ut)
build_test_folder(linux_reals_ut)
build_test_folder(sync_linux_ut)
build_test_folder(sysinfo_linux_ut)
build_test_folder(timer_linux_ut)
build_test_folder(gballoc_ll_passthrough_ut)
build_test_folder(gballoc_hl_passthrough_ut)

Просмотреть файл

@ -0,0 +1,19 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
cmake_minimum_required(VERSION 2.8.11)
set(theseTestsName sysinfo_linux_ut)
set(${theseTestsName}_test_files
${theseTestsName}.c
)
set(${theseTestsName}_c_files
sysinfo_linux_mocked.c
)
set(${theseTestsName}_h_files
)
build_test_artifacts(${theseTestsName} ON "tests/c_pal/win32" ADDITIONAL_LIBS pal_interfaces c_pal_reals)

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stddef.h>
#include "testrunnerswitcher.h"
int main(void)
{
size_t failedTestCount = 0;
RUN_TEST_SUITE(sysinfo_linux_unittests, failedTestCount);
return (int)failedTestCount;
}

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) Microsoft. All rights reserved.
#include <unistd.h>
#define sysconf mocked_sysconf
extern long mocked_sysconf(int name);
#include "../../src/sysinfo_linux.c"

Просмотреть файл

@ -0,0 +1,148 @@
// Copyright(C) Microsoft Corporation.All rights reserved.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <unistd.h>
#include "macro_utils/macro_utils.h"
#include "testrunnerswitcher.h"
#include "umock_c/umock_c.h"
#include "umock_c/umocktypes_stdint.h"
#include "umock_c/umocktypes.h"
#define ENABLE_MOCKS
#include "umock_c/umock_c_prod.h"
#ifdef __cplusplus
extern "C" {
#endif
MOCKABLE_FUNCTION(, long, mocked_sysconf, int, name)
#ifdef __cplusplus
}
#endif
#undef ENABLE_MOCKS
#include "c_pal/sysinfo.h"
static TEST_MUTEX_HANDLE test_serialize_mutex;
static const uint32_t TEST_PROC_COUNT = 4;
MU_DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES)
static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code)
{
ASSERT_FAIL("umock_c reported error :%" PRI_MU_ENUM "", MU_ENUM_VALUE(UMOCK_C_ERROR_CODE, error_code));
}
BEGIN_TEST_SUITE(sysinfo_linux_unittests)
TEST_SUITE_INITIALIZE(suite_init)
{
test_serialize_mutex = TEST_MUTEX_CREATE();
ASSERT_IS_NOT_NULL(test_serialize_mutex);
ASSERT_ARE_EQUAL(int, 0, umock_c_init(on_umock_c_error), "umock_c_init failed");
ASSERT_ARE_EQUAL(int, 0, umocktypes_stdint_register_types(), "umocktypes_stdint_register_types failed");
}
TEST_SUITE_CLEANUP(suite_cleanup)
{
umock_c_deinit();
TEST_MUTEX_DESTROY(test_serialize_mutex);
}
TEST_FUNCTION_INITIALIZE(init)
{
if (TEST_MUTEX_ACQUIRE(test_serialize_mutex))
{
ASSERT_FAIL("Could not acquire test serialization mutex.");
}
umock_c_reset_all_calls();
}
TEST_FUNCTION_CLEANUP(cleanup)
{
TEST_MUTEX_RELEASE(test_serialize_mutex);
}
/* sysinfo_get_processor_count */
/* Tests_SRS_SYSINFO_LINUX_01_001: [ sysinfo_get_processor_count shall call sysconf with SC_NPROCESSORS_ONLN to obtain the number of configured processors. ]*/
TEST_FUNCTION(sysinfo_get_processor_count_returns_the_result_of_sysconf)
{
//arrange
STRICT_EXPECTED_CALL(mocked_sysconf(_SC_NPROCESSORS_ONLN))
.SetReturn(TEST_PROC_COUNT);
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, TEST_PROC_COUNT, proc_count);
}
/* Tests_SRS_SYSINFO_LINUX_01_001: [ sysinfo_get_processor_count shall call sysconf with SC_NPROCESSORS_ONLN to obtain the number of configured processors. ]*/
TEST_FUNCTION(sysinfo_get_processor_count_returns_the_result_of_sysconf_33)
{
//arrange
STRICT_EXPECTED_CALL(mocked_sysconf(_SC_NPROCESSORS_ONLN))
.SetReturn(33);
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, 33, proc_count);
}
/* Tests_SRS_SYSINFO_LINUX_01_002: [ If any error occurs, sysinfo_get_processor_count shall return 0. ]*/
TEST_FUNCTION(when_sysconf_fails_sysinfo_get_processor_count_returns_0)
{
//arrange
STRICT_EXPECTED_CALL(mocked_sysconf(_SC_NPROCESSORS_ONLN))
.SetReturn(-1);
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, 0, proc_count);
}
/* Tests_SRS_SYSINFO_LINUX_01_003: [ If sysconf returns a number bigger than UINT32_MAX, sysinfo_get_processor_count shall fail and return 0. ]*/
TEST_FUNCTION(when_sysconf_returns_UINT32_MAX_sysinfo_get_processor_count_succeeds)
{
//arrange
STRICT_EXPECTED_CALL(mocked_sysconf(_SC_NPROCESSORS_ONLN))
.SetReturn(UINT32_MAX);
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, UINT32_MAX, proc_count);
}
/* Tests_SRS_SYSINFO_LINUX_01_003: [ If sysconf returns a number bigger than UINT32_MAX, sysinfo_get_processor_count shall fail and return 0. ]*/
TEST_FUNCTION(when_sysconf_returns_more_than_UINT32_MAX_sysinfo_get_processor_count_returns_0)
{
//arrange
STRICT_EXPECTED_CALL(mocked_sysconf(_SC_NPROCESSORS_ONLN))
.SetReturn(UINT32_MAX + 1);
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, 0, proc_count);
}
END_TEST_SUITE(sysinfo_linux_unittests)

Просмотреть файл

@ -36,6 +36,7 @@ set(pal_win32_c_files
src/string_utils.c
src/timer_win32.c
src/sync_win32.c
src/sysinfo_win32.c
src/file_win32.c
src/${gballoc_ll_c}
src/${gballoc_hl_c}

Просмотреть файл

@ -0,0 +1,24 @@
# sysinfo_win32
================
## Overview
`sysinfo_win32` provides the Windows implementation for `sysinfo`.
## Exposed API
```c
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
```
### sysinfo_get_processor_count
```c
MOCKABLE_FUNCTION(, uint32_t, sysinfo_get_processor_count);
```
`sysinfo_get_processor_count` returns the processor count as returned by the operating system.
**SRS_SYSINFO_WIN32_01_001: [** `sysinfo_get_processor_count` shall call `GetSystemInfo` to obtain the system information. **]**
**SRS_SYSINFO_WIN32_01_002: [** `sysinfo_get_processor_count` shall return the processor count as returned by `GetSystemInfo`. **]**

28
win32/src/sysinfo_win32.c Normal file
Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (C) Microsoft Corporation. All rights reserved.
#include <inttypes.h>
#include "windows.h"
#include "c_logging/xlogging.h"
#include "c_pal/sysinfo.h"
uint32_t sysinfo_get_processor_count(void)
{
SYSTEM_INFO system_info;
uint32_t result;
/* Maybe as an improvement we should use GetLogicalProcessorInformation (https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation) */
/* Someday ... */
/* Codes_SRS_SYSINFO_01_001: [ sysinfo_get_processor_count shall obtain the processor count as reported by the operating system. ]*/
/* Codes_SRS_SYSINFO_WIN32_01_001: [ sysinfo_get_processor_count shall call GetSystemInfo to obtain the system information. ]*/
GetSystemInfo(&system_info);
/* Codes_SRS_SYSINFO_WIN32_01_002: [ sysinfo_get_processor_count shall return the processor count as returned by GetSystemInfo. ]*/
result = system_info.dwNumberOfProcessors;
LogInfo("Detected %" PRIu32 " processors", result);
return result;
}

Просмотреть файл

@ -12,6 +12,7 @@ if(${run_unittests})
build_test_folder(srw_lock_win32_ut)
build_test_folder(reals_win32_ut)
build_test_folder(sync_win32_ut)
build_test_folder(sysinfo_win32_ut)
build_test_folder(file_win32_ut)
build_test_folder(gballoc_hl_metrics_ut)

Просмотреть файл

@ -0,0 +1,19 @@
#Copyright (c) Microsoft. All rights reserved.
#Licensed under the MIT license. See LICENSE file in the project root for full license information.
cmake_minimum_required(VERSION 2.8.11)
set(theseTestsName sysinfo_win32_ut)
set(${theseTestsName}_test_files
${theseTestsName}.c
)
set(${theseTestsName}_c_files
sysinfo_win32_mocked.c
)
set(${theseTestsName}_h_files
)
build_test_artifacts(${theseTestsName} ON "tests/c_pal/win32" ADDITIONAL_LIBS pal_interfaces c_pal_reals)

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stddef.h>
#include "testrunnerswitcher.h"
int main(void)
{
size_t failedTestCount = 0;
RUN_TEST_SUITE(sysinfo_win32_unittests, failedTestCount);
return (int)failedTestCount;
}

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) Microsoft. All rights reserved.
#include "windows.h"
#define GetSystemInfo mocked_GetSystemInfo
extern void mocked_GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
#include "../../src/sysinfo_win32.c"

Просмотреть файл

@ -0,0 +1,116 @@
// Copyright(C) Microsoft Corporation.All rights reserved.
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include "windows.h"
#include "macro_utils/macro_utils.h"
#include "testrunnerswitcher.h"
#include "umock_c/umock_c.h"
#include "umock_c/umocktypes_stdint.h"
#include "umock_c/umocktypes.h"
#include "umock_c/umock_c_negative_tests.h"
#define ENABLE_MOCKS
#include "umock_c/umock_c_prod.h"
#ifdef __cplusplus
extern "C" {
#endif
MOCKABLE_FUNCTION(, void, mocked_GetSystemInfo, LPSYSTEM_INFO, lpSystemInfo)
#ifdef __cplusplus
}
#endif
#undef ENABLE_MOCKS
#include "c_pal/sysinfo.h"
static TEST_MUTEX_HANDLE test_serialize_mutex;
static const uint32_t TEST_PROC_COUNT = 4;
MU_DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES)
static void on_umock_c_error(UMOCK_C_ERROR_CODE error_code)
{
ASSERT_FAIL("umock_c reported error :%" PRI_MU_ENUM "", MU_ENUM_VALUE(UMOCK_C_ERROR_CODE, error_code));
}
BEGIN_TEST_SUITE(sysinfo_win32_unittests)
TEST_SUITE_INITIALIZE(suite_init)
{
test_serialize_mutex = TEST_MUTEX_CREATE();
ASSERT_IS_NOT_NULL(test_serialize_mutex);
ASSERT_ARE_EQUAL(int, 0, umock_c_init(on_umock_c_error), "umock_c_init failed");
ASSERT_ARE_EQUAL(int, 0, umocktypes_stdint_register_types(), "umocktypes_stdint_register_types failed");
REGISTER_UMOCK_ALIAS_TYPE(LPSYSTEM_INFO, void*);
}
TEST_SUITE_CLEANUP(suite_cleanup)
{
umock_c_deinit();
umock_c_negative_tests_deinit();
TEST_MUTEX_DESTROY(test_serialize_mutex);
}
TEST_FUNCTION_INITIALIZE(init)
{
if (TEST_MUTEX_ACQUIRE(test_serialize_mutex))
{
ASSERT_FAIL("Could not acquire test serialization mutex.");
}
umock_c_reset_all_calls();
}
TEST_FUNCTION_CLEANUP(cleanup)
{
TEST_MUTEX_RELEASE(test_serialize_mutex);
}
/* sysinfo_get_processor_count */
/* Tests_SRS_SYSINFO_WIN32_01_001: [ sysinfo_get_processor_count shall call GetSystemInfo to obtain the system information. ]*/
/* Tests_SRS_SYSINFO_WIN32_01_002: [ sysinfo_get_processor_count shall return the processor count as returned by GetSystemInfo. ]*/
TEST_FUNCTION(sysinfo_get_processor_count_returns_the_processor_count)
{
//arrange
SYSTEM_INFO test_system_info = { 0 };
test_system_info.dwNumberOfProcessors = TEST_PROC_COUNT;
STRICT_EXPECTED_CALL(mocked_GetSystemInfo(IGNORED_ARG))
.CopyOutArgumentBuffer_lpSystemInfo(&test_system_info, sizeof(test_system_info));
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, TEST_PROC_COUNT, proc_count);
}
/* Tests_SRS_SYSINFO_WIN32_01_001: [ sysinfo_get_processor_count shall call GetSystemInfo to obtain the system information. ]*/
/* Tests_SRS_SYSINFO_WIN32_01_002: [ sysinfo_get_processor_count shall return the processor count as returned by GetSystemInfo. ]*/
TEST_FUNCTION(sysinfo_get_processor_count_returns_the_processor_count_33)
{
//arrange
SYSTEM_INFO test_system_info = { 0 };
test_system_info.dwNumberOfProcessors = 33;
STRICT_EXPECTED_CALL(mocked_GetSystemInfo(IGNORED_ARG))
.CopyOutArgumentBuffer_lpSystemInfo(&test_system_info, sizeof(test_system_info));
//act
uint32_t proc_count = sysinfo_get_processor_count();
//assert
ASSERT_ARE_EQUAL(uint32_t, 33, proc_count);
}
END_TEST_SUITE(sysinfo_win32_unittests)