From a2125c2b9fad8b1de14c97afa90e004dfd649f30 Mon Sep 17 00:00:00 2001 From: Lamdonn Date: Fri, 15 Nov 2024 00:31:10 +0800 Subject: [PATCH] Add cpul, date and unitt --- README.en.md | 10 + README.md | 10 + makefile | 8 +- source/00_application/console/console.c | 10 +- source/01_general/date.c | 234 ++++++++++++++++++ source/01_general/date.h | 120 ++++++++++ source/06_performance/cpul.c | 211 ++++++++++++++++ source/06_performance/cpul.h | 100 ++++++++ source/06_performance/unitt.c | 306 ++++++++++++++++++++++++ source/06_performance/unitt.h | 184 ++++++++++++++ test/test.mk | 7 +- test/test_cpul.c | 200 ++++++++++++++++ test/test_date.c | 69 ++++++ test/test_ramt.c | 43 ++++ test/test_unitt.c | 182 ++++++++++++++ 15 files changed, 1688 insertions(+), 6 deletions(-) create mode 100644 source/01_general/date.c create mode 100644 source/01_general/date.h create mode 100644 source/06_performance/cpul.c create mode 100644 source/06_performance/cpul.h create mode 100644 source/06_performance/unitt.c create mode 100644 source/06_performance/unitt.h create mode 100644 test/test_cpul.c create mode 100644 test/test_date.c create mode 100644 test/test_ramt.c create mode 100644 test/test_unitt.c diff --git a/README.en.md b/README.en.md index 4831cdd..f0a0e80 100644 --- a/README.en.md +++ b/README.en.md @@ -2,6 +2,11 @@ ![logo](/image/logo.png) +[![Version](https://img.shields.io/badge/version-0.2.0-blue.svg)](https://gitee.com/Lamdonn/varch) +[![License](https://img.shields.io/badge/license-GPL%202.0-brightgreen.svg)](LICENSE) +[![Author](https://img.shields.io/badge/author-Lamdonn%20%20%20%20%20-brightblue.svg)](Lamdonn@163.com) +![Supported Platforms](https://img.shields.io/badge/platform-Linux%20&%20MinGW-yellow.svg) + ## Introduction [中文版](README.md) @@ -30,6 +35,7 @@ It has the characteristics of **simplicity, universality, and efficiency**, with | valloc | 01.00.00 | [link](/doc/valloc.md) | [path](./source/01_general) | Dynamic memory usage testing tool | vlog | 01.01.00 | [link](/doc/vlog.md) | [path](./source/01_general) | Log output module | intl | 01.00.00 | [link](/doc/intl.md) | [path](./source/01_general) | Large integer arithmetic module +| date | 01.00.00 | [link](/doc/date.md) | [path](./source/01_general) | Date calculation module, calculating date differences, printing calendars, etc | vctype | 01.00.00 | [link](/doc/vctype.md) | [path](./source/02_vstd) | Similar to the C standard library ctype | vmath | 01.00.00 | [link](/doc/vmath.md) | [path](./source/02_vstd) | Similar to the C standard library math | vmem | 01.00.00 | [link](/doc/vmem.md) | [path](./source/02_vstd) | Simple implementation of memory pool @@ -62,6 +68,10 @@ It has the characteristics of **simplicity, universality, and efficiency**, with | json | 01.00.00 | [link](/doc/json.md) | [path](./source/05_parser) | JSON file parsing generator | txls | 01.00.00 | [link](/doc/txls.md) | [path](./source/05_parser) | TXLS file parsing generator | xml | 01.00.00 | [link](/doc/xml.md) | [path](./source/05_parser) | XML file parsing generator +| ramt | 01.00.00 | [link](/doc/ramt.md) | [path](./source/06_performance) | RAM test module +| romt | 01.00.00 | [link](/doc/romt.md) | [path](./source/06_performance) | ROM test module +| cpul | 01.00.00 | [link](/doc/cpul.md) | [path](./source/06_performance) | CPU load test module, including obtaining and increasing load +| unitt | 01.00.00 | [link](/doc/unitt.md) | [path](./source/06_performance) | Simple unit test module ## Usage diff --git a/README.md b/README.md index 8b21d9f..2a2e591 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ ![logo](/image/logo.png) +[![Version](https://img.shields.io/badge/version-0.2.0-blue.svg)](https://gitee.com/Lamdonn/varch) +[![License](https://img.shields.io/badge/license-GPL%202.0-brightgreen.svg)](LICENSE) +[![Author](https://img.shields.io/badge/author-Lamdonn%20%20%20%20%20-brightblue.svg)](Lamdonn@163.com) +![Supported Platforms](https://img.shields.io/badge/platform-Linux%20&%20MinGW-yellow.svg) + ## 介绍 [English version](README.en.md) @@ -30,6 +35,7 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用 | valloc | 01.00.00 | [link](/doc/valloc.md) | [path](./source/01_general) | 动态内存使用测试工具 | vlog | 01.01.00 | [link](/doc/vlog.md) | [path](./source/01_general) | 日志输出模块 | intl | 01.00.00 | [link](/doc/intl.md) | [path](./source/01_general) | 大型整数运算模块 +| date | 01.00.00 | [link](/doc/date.md) | [path](./source/01_general) | 日期计算模块,计算日期差、打印日历等 | vctype | 01.00.00 | [link](/doc/vctype.md) | [path](./source/02_vstd) | 类似于C标准库ctype | vmath | 01.00.00 | [link](/doc/vmath.md) | [path](./source/02_vstd) | 类似于C标准库math | vmem | 01.00.00 | [link](/doc/vmem.md) | [path](./source/02_vstd) | 内存池的简单实现 @@ -62,6 +68,10 @@ varch(we-architecture,意为我们的框架库)是嵌入式C语言常用 | json | 01.00.00 | [link](/doc/json.md) | [path](./source/05_parser) | JSON文件解析生成器 | txls | 01.00.00 | [link](/doc/txls.md) | [path](./source/05_parser) | TXLS文件解析生成器 | xml | 01.00.00 | [link](/doc/xml.md) | [path](./source/05_parser) | XML文件解析生成器 +| ramt | 01.00.00 | [link](/doc/ramt.md) | [path](./source/06_performance) | RAM测试模块 +| romt | 01.00.00 | [link](/doc/romt.md) | [path](./source/06_performance) | ROM测试模块 +| cpul | 01.00.00 | [link](/doc/cpul.md) | [path](./source/06_performance) | CPU负载测试模块,包含获取和增加负载 +| unitt | 01.00.00 | [link](/doc/unitt.md) | [path](./source/06_performance) | 简易的单元测试模块 ## 使用说明 diff --git a/makefile b/makefile index fd9d55d..97a8b9b 100644 --- a/makefile +++ b/makefile @@ -58,6 +58,12 @@ include $(TESTSPACE)/test.mk TESTSRC += $(APPLICATION_PATH)/main.c TESTSRC += $(TEST_SRC) +ifeq ($(OS),Windows_NT) + UNAME := Windows +else + UNAME := $(shell uname -s) +endif + ################################################################################## ### recipes ################################################################################## @@ -79,7 +85,7 @@ LIBP ?= /usr # link ${TARP}:$(OBJS) - mkdir -p $(dir $@) + @ mkdir -p $(dir $@) @ $(CC) $(CFLAG) $(OBJS) -o $(TARP) $(LIBS) # compile diff --git a/source/00_application/console/console.c b/source/00_application/console/console.c index 1b3221b..0179a78 100644 --- a/source/00_application/console/console.c +++ b/source/00_application/console/console.c @@ -8,6 +8,7 @@ #include "init.h" #if defined(_WIN32) #include +#include #elif defined(__unix) #include #endif @@ -39,9 +40,9 @@ static int kbhit(void) if (ch != EOF) { ungetc(ch, stdin); - return 0; + return 1; } - return 1; + return 0; } #endif @@ -67,8 +68,8 @@ static int into(int argc, char *argv[]) static void console_main(void) { - int c; - if (!kbhit()) + int c = 0; + if (kbhit()) { c = getchar(); #if CONSOLE_DEBUG == 1 @@ -124,6 +125,7 @@ void console_init(void) if (!console_task) return; printf("console init! task<%d>!\r\n", console_task); + printf("Press `Enter` to enter the console, input `cmd -h` to get help!\r\n"); /* Export into command */ command_export("into", into); diff --git a/source/01_general/date.c b/source/01_general/date.c new file mode 100644 index 0000000..31545df --- /dev/null +++ b/source/01_general/date.c @@ -0,0 +1,234 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file date.c + * \unit date + * \brief This is a simple date calculate module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#include "date.h" + +// TODO: 1582.10.04 - 1582.10.15 + +/** + * \brief Check if a year is a leap year. + * \param[in] year: The year to check. + * \return 1 if the year is a leap year, 0 otherwise. + */ +uint8_t date_isleap(uint16_t year) +{ + return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)); +} + +/** + * \brief Get the number of days in a century. + * \param[in] century: The century to evaluate. + * \return Number of days in the given century. + */ +uint32_t date_century_days(uint16_t century) +{ + if (century == 0) return 0u; // No days in century 0 + return (century % 4 == 0) ? 36525u : 36524u; // 25 leap years in 400 years +} + +/** + * \brief Get the number of days in a year. + * \param[in] year: The year to evaluate. + * \return Number of days in the given year. + */ +uint32_t date_year_days(uint16_t year) +{ + if (year == 0) return 0u; // No days in year 0 + return date_isleap(year) ? 366u : 365u; +} + +/** + * \brief Get the number of days in a month of a given year. + * \param[in] year: The year of the month. + * \param[in] month: The month to evaluate (1-12). + * \return Number of days in the specified month of the specified year. + */ +uint32_t date_month_days(uint16_t year, uint8_t month) +{ + if (year == 0) return 0; // No valid month days for year 0 + switch (month) + { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; // Months with 31 days + case 4: case 6: case 9: case 11: + return 30; // Months with 30 days + case 2: + return date_isleap(year) ? 29 : 28; // February days depending on leap year + default: + return 0; // Invalid month + } +} + +/** + * \brief Validate a date. + * \param[in] date: The date structure to validate. + * \return 1 if the date is valid, 0 otherwise. + */ +uint8_t date_isvalid(DATE date) +{ + if (date.year == 0 || date.month == 0 || date.day == 0) return 0; // Year, month or day 0 is not valid + return (date_month_days(date.year, date.month) >= date.day); +} + +/** + * \brief Calculate the total number of days from a given date to a base date. + * \param[in] date: The date to calculate the total days for. + * \return Total number of days from a base date to the given date, 0 if invalid. + */ +uint32_t date_current_days(DATE date) +{ + uint32_t days = 0; + uint16_t year = 1; + uint8_t month = 1; + + // Validate the input date; return 0 if invalid + if (!date_isvalid(date)) return 0; + + // Count days for complete centuries + for ( ; year + 2000 <= date.year; year += 2000) days += 730485u; + // Count days for complete centuries within the current century + for ( ; year + 100 <= date.year; year += 100) days += date_century_days((year / 100) + 1); + // Count days for complete years within the current century + for ( ; year + 1 <= date.year; year++) days += date_year_days(year); + // Count days for completed months in the current year + for ( ; month < date.month; month++) days += date_month_days(date.year, month); + // Add the days of the current month + days += date.day; + + return days; +} + +/** + * \brief Get the week number of a given date based on the total days. + * \param[in] date: The date to evaluate. + * \return The week number [1, 7] for the specified date (Mon | Tue | Wed | Thu | Fri | Sat | Sun), 0 if invalid. + */ +uint32_t date_get_week(DATE date) +{ + #define bias 0 // Adjust to week start + uint32_t days = date_current_days(date); + uint32_t week = 0; + + // If days is 0, return 0 indicating invalid date + if (days == 0) return 0; + + week = (days + bias) % 7; + if (week == 0) week = 7; + + return week; +} + +/** + * \brief Calculate the difference in days between two dates. + * \param[in] date1: The first date. + * \param[in] date2: The second date. + * \return The difference in days between the two dates. Returns 0 if either date is invalid. + */ +int32_t date_diff_days(DATE date1, DATE date2) +{ + uint32_t days1 = date_current_days(date1); + uint32_t days2 = date_current_days(date2); // Corrected to use date2 + + // Return 0 if either date is invalid + if (days1 == 0 || days2 == 0) return 0; + + return (int32_t)(days1 - days2); +} + +/** + * \brief Convert a number of days to a DATE structure. + * \param[in] days: The number of days to convert. + * \return A DATE structure representing the converted days. + */ +DATE date_from_days(uint32_t days) +{ + DATE date = {1, 1, 1}; // Initialize to base date (1/1/1) + uint32_t tdays = 0; + + // Return zero date if days are 0 + if (days == 0) return DATE(0,0,0); + + // Convert days to years + for ( ; days > 730485; days -= 730485) date.year += 2000; + for ( ; days > (tdays = date_century_days((date.year / 100) + 1)); days -= tdays) date.year += 100; + for ( ; days > (tdays = date_year_days(date.year)); days -= tdays) date.year++; + for ( ; days > (tdays = date_month_days(date.year, date.month)); days -= tdays) date.month++; + date.day = days; + + return date; +} + +/** + * \brief Offset a date by a certain number of days. + * \param[in] date: The date to offset. + * \param[in] days: The number of days to offset (can be negative). + * \return A new DATE structure after applying the offset, or a zero date if invalid. + */ +DATE date_offset(DATE date, int32_t days) +{ + if (!date_isvalid(date)) return DATE(0,0,0); // Return zero date if invalid + return date_from_days(date_current_days(date) + days); +} + +/** + * \brief Show the calendar for a specific month and year. + * \param[in] year: The year of the calendar to show. + * \param[in] month: The month of the calendar to show. + */ +void date_show(uint16_t year, uint8_t month) +{ + DATE date = {year, month, 1}; + uint32_t days; + uint32_t tday = 1; + uint32_t week = 0; + int len = 0; + + days = date_month_days(year, month); + if (days == 0) + { + printf("[ERROR] Invalid date!\r\n"); + return; // Exit if the date is invalid + } + + week = date_get_week(date) % 7; // Get the starting day of the week + + // Print the calendar header + printf("+-----------------------------------------+\r\n"); + len = printf("| %04d/%02d", year, month); while (len++ < 42) printf(" "); printf("|\r\n"); + printf("+-----------------------------------------+\r\n"); + printf("| Sun | Mon | Tue | Wed | Thu | Fri | Sat |\r\n"); + printf("+-----------------------------------------+\r\n"); + + // Print the days of the month + while (tday <= days) + { + for (int i = 0; i < 7; i++) + { + if (i == 0) printf("|"); // Start of the week + + if (i == week && tday <= days) + { + printf(" %3u |", tday); // Print the current day + tday++; + week = (week + 1) % 7; // Move to the next week day + } + else + { + printf(" |"); // Empty space for days not in the current month + } + + if (i == 6) printf("\r\n"); // End of the week + } + } + + printf("+-----------------------------------------+\r\n"); // End of the calendar +} diff --git a/source/01_general/date.h b/source/01_general/date.h new file mode 100644 index 0000000..58c68c8 --- /dev/null +++ b/source/01_general/date.h @@ -0,0 +1,120 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file date.h + * \unit date + * \brief This is a simple date calculate module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __date_H +#define __date_H + +#include +#include + +/* Version infomation */ + +#define DATE_V_MAJOR 1 +#define DATE_V_MINOR 0 +#define DATE_V_PATCH 0 + +typedef struct { + uint16_t year; /**< Year component of the date */ + uint8_t month; /**< Month component of the date */ + uint8_t day; /**< Day component of the date */ +} DATE; + +/** + * \brief Macro to create a DATE structure instance. + * \param[in] y: Year component of the date. + * \param[in] m: Month component of the date (1-12). + * \param[in] d: Day component of the date (1-31 depending on the month). + * \return A DATE structure initialized with the specified year, month, and day. + */ +#define DATE(y, m, d) (DATE){.year=(y), .month=(m), .day=(d)} + +/** + * \brief Check if a year is a leap year. + * \param[in] year: The year to check. + * \return 1 if the year is a leap year, 0 otherwise. + */ +uint8_t date_isleap(uint16_t year); + +/** + * \brief Validate a date. + * \param[in] date: The date structure to validate. + * \return 1 if the date is valid, 0 otherwise. + */ +uint8_t date_isvalid(DATE date); + +/** + * \brief Get the number of days in a century. + * \param[in] century: The century to evaluate. + * \return Number of days in the given century. + */ +uint32_t date_century_days(uint16_t century); + +/** + * \brief Get the number of days in a year. + * \param[in] year: The year to evaluate. + * \return Number of days in the given year. + */ +uint32_t date_year_days(uint16_t year); + +/** + * \brief Get the number of days in a month of a given year. + * \param[in] year: The year of the month. + * \param[in] month: The month to evaluate (1-12). + * \return Number of days in the specified month of the specified year. + */ +uint32_t date_month_days(uint16_t year, uint8_t month); + +/** + * \brief Get the week number of a given date based on the total days. + * \param[in] date: The date to evaluate. + * \return The week number [1, 7] for the specified date (Mon | Tue | Wed | Thu | Fri | Sat | Sun), 0 if invalid. + */ +uint32_t date_get_week(DATE date); + +/** + * \brief Calculate the total number of days from a given date to a base date. + * \param[in] date: The date to calculate the total days for. + * \return Total number of days from a base date to the given date, 0 if invalid. + */ +uint32_t date_current_days(DATE date); + +/** + * \brief Calculate the difference in days between two dates. + * \param[in] date1: The first date. + * \param[in] date2: The second date. + * \return The difference in days between the two dates. Returns 0 if either date is invalid. + */ +int32_t date_diff_days(DATE date1, DATE date2); + +/** + * \brief Convert a number of days to a DATE structure. + * \param[in] days: The number of days to convert. + * \return A DATE structure representing the converted days. + */ +DATE date_from_days(uint32_t days); + +/** + * \brief Offset a date by a certain number of days. + * \param[in] date: The date to offset. + * \param[in] days: The number of days to offset (can be negative). + * \return A new DATE structure after applying the offset, or a zero date if invalid. + */ +DATE date_offset(DATE date, int32_t days); + +/** + * \brief Show the calendar for a specific month and year. + * \param[in] year: The year of the calendar to show. + * \param[in] month: The month of the calendar to show. + */ +void date_show(uint16_t year, uint8_t month); + +#endif diff --git a/source/06_performance/cpul.c b/source/06_performance/cpul.c new file mode 100644 index 0000000..b30aa59 --- /dev/null +++ b/source/06_performance/cpul.c @@ -0,0 +1,211 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file cpul.c + * \unit cpul + * \brief This is a simple cpuload module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#include "cpul.h" +#include +#include + +// Buffer for CRC calculation, initialized with some values +uint8_t calbuffer[CPUL_GEN_BSIZE] = {'A', 'B', 0}; + +/** + * \brief Adjust the refined load based on current and target loads. + * + * This function controls the refined load adjustment by comparing + * the current load with the target load and modifying the refined + * load accordingly. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \return Returns the adjusted refined load value. + */ +static uint32_t controller(CPUL *cpul) +{ + // If the current load is less than the target load + if (cpul->ctrl.cload < cpul->ctrl.tload) + { + // If adding resolution to refined load does not exceed its current value + if (cpul->ctrl.refine + cpul->resolution > cpul->ctrl.refine) + { + // Increase the refined load by the resolution value + cpul->ctrl.refine += cpul->resolution; + } + } + // If the current load is greater than target load + 1 + else if (cpul->ctrl.cload > (cpul->ctrl.tload + 1)) + { + // If the refined load is greater than or equal to the resolution + if (cpul->ctrl.refine >= cpul->resolution) + { + // Decrease the refined load by the resolution value + cpul->ctrl.refine -= cpul->resolution; + } + } + + return cpul->ctrl.refine; // Return the adjusted refined load +} + +/** + * \brief Calculate CRC8 checksum. + * + * This function computes the CRC8 checksum for a given data buffer. + * It iterates through each byte of data and processes it to generate + * the CRC value. + * + * \param[in] data: Pointer to the data buffer. + * \param[in] len: Length of the data buffer. + * \return Returns the calculated CRC8 value. + */ +static uint8_t crc8(uint8_t *data, uint32_t len) +{ + uint8_t i; // Loop index for bit processing + uint8_t crc = 0; // Initialize CRC value to 0 + while (len--) // Process each byte in the data buffer + { + crc ^= *data++; // XOR the current byte with the CRC value + for (i = 0; i < 8; i++) // Process each bit of the byte + { + if (crc & 0x80) // If the highest bit of CRC is set + crc = (crc << 1) ^ 0x07; // Shift left and XOR with the polynomial + else + crc <<= 1; // Just shift left if the highest bit is not set + } + } + return crc; // Return the calculated CRC8 value +} + +/** + * \brief Update the granularity of the load control. + * + * This function updates the calbuffer values based on the refined load + * using CRC8 checksum for each iteration specified by the input parameter. + * + * \param[in] input: Number of iterations to update the buffer. + * \return none. + */ +static void granularity(uint32_t input) +{ + // Loop through the specified number of iterations + for (uint32_t i = 0; i < input; i++) + { + // Update calbuffer with a CRC8 value calculated from the current buffer + calbuffer[calbuffer[0] % sizeof(calbuffer)] = crc8(calbuffer, sizeof(calbuffer)); + } +} + +/** + * \brief Initialize the CPUL instance. + * + * This function initializes the CPUL structure to default values + * and checks for valid pointers. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_init(CPUL *cpul) +{ + // Check if the cpul pointer is valid + if (!cpul) return CPUL_E_INVALID; + // Check if the raw function pointer is valid + if (!cpul->raw) return CPUL_E_RAW; + + cpul->ctrl.cload = 0xFFFF; // Set current load to untested value + cpul->ctrl.tload = 0; // Default target load to zero (no load increase) + cpul->ctrl.refine = 0; // Initialize refined load + + return CPUL_E_OK; // Initialization successful +} + +/** + * \brief Get the current CPU load. + * + * This function retrieves the current load from the CPUL instance + * and checks for validity of parameters and state. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \param[out] load: Pointer to store the current load value. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_get(CPUL *cpul, uint16_t *load) +{ + // Check if the cpul pointer is valid + if (!cpul) return CPUL_E_INVALID; + // Check if the raw function pointer is valid + if (!cpul->raw) return CPUL_E_RAW; + // Check if the load parameter is valid + if (!load) return CPUL_E_PARA; + + // If current load is still untested, return an error + if (cpul->ctrl.cload == 0xFFFF) return CPUL_E_NTEST; + // Check if the current load exceeds the maximum allowed value + if (cpul->ctrl.cload > 10000) return CPUL_E_OVER; + + *load = cpul->ctrl.cload; // Retrieve the current load value + + return CPUL_E_OK; // Success +} + +/** + * \brief Set the target CPU load. + * + * This function sets the target load for the CPUL instance and checks for valid parameters. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \param[in] load: Target load value to set. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_set(CPUL *cpul, uint16_t load) +{ + // Check if the cpul pointer is valid + if (!cpul) return CPUL_E_INVALID; + // Check if the raw function pointer is valid + if (!cpul->raw) return CPUL_E_RAW; + // Check if the load parameter is zero + if (!load) return CPUL_E_PARA; + + // Check if the load exceeds the maximum allowed value + if (load > 10000) return CPUL_E_OVER; + + cpul->ctrl.tload = load; // Set the target load + + return CPUL_E_OK; // Success +} + +/** + * \brief Execute a CPUL management task. + * + * This function executes a task to manage the CPU load based on + * the current and target load values. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_task(CPUL *cpul) +{ + // Check if the cpul pointer is valid + if (!cpul) return CPUL_E_INVALID; + // Check if the raw function pointer is valid + if (!cpul->raw) return CPUL_E_RAW; + + // Call the raw function to get the current load value + cpul->ctrl.cload = cpul->raw(cpul->coreid); + + // If the target load is not zero, perform load management + if (cpul->ctrl.tload != 0) + { + // Adjust the refined load based on current and target load + cpul->ctrl.refine = controller(cpul); + // Update granularity based on the refined load + granularity(cpul->ctrl.refine); + } + + return CPUL_E_OK; // Success +} diff --git a/source/06_performance/cpul.h b/source/06_performance/cpul.h new file mode 100644 index 0000000..f9fdd9e --- /dev/null +++ b/source/06_performance/cpul.h @@ -0,0 +1,100 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file cpul.h + * \unit cpul + * \brief This is a simple cpuload module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __cpul_H +#define __cpul_H + +#include "stdint.h" + +/* Version infomation */ +#define CPUL_V_MAJOR 0 +#define CPUL_V_MINOR 1 +#define CPUL_V_PATcH 0 + +#define CPUL_GEN_BSIZE 4 + +#define CPUL_E_OK 0 // Success +#define CPUL_E_INVALID 1 // Invalid `CPUL` pointer +#define CPUL_E_RAW 2 // Invalid raw function +#define CPUL_E_PARA 3 // Invalid parameter +#define CPUL_E_NTEST 4 // CPUL load testing has not started +#define CPUL_E_OVER 5 // CPUL load exceeds range + +typedef uint16_t (*cpul_raw_t)(uint8_t coreid); // Type definition for the raw CPUL load function + +/** + * \brief Structure to control CPUL load parameters. + */ +typedef struct +{ + uint32_t refine; ///< Refined load value + uint16_t cload; ///< Current load value + uint16_t tload; ///< Target load value +} CPUL_CTRL; + +/** + * \brief Structure to represent a CPU Load Manager. + */ +typedef struct +{ + uint8_t coreid; ///< Core ID + cpul_raw_t raw; ///< Pointer to the raw CPUL load function + uint32_t resolution; ///< Resolution of the load control + CPUL_CTRL ctrl; ///< Control structure for CPUL management +} CPUL; + +/** + * \brief Initialize the CPUL instance. + * + * This function initializes the CPUL structure to default values + * and checks for valid pointers. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_init(CPUL *cpul); + +/** + * \brief Get the current CPU load. + * + * This function retrieves the current load from the CPUL instance + * and checks for validity of parameters and state. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \param[out] load: Pointer to store the current load value. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_get(CPUL *cpul, uint16_t *load); + +/** + * \brief Set the target CPU load. + * + * This function sets the target load for the CPUL instance and checks for valid parameters. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \param[in] load: Target load value to set. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_set(CPUL *cpul, uint16_t load); + +/** + * \brief Execute a CPUL management task. + * + * This function executes a task to manage the CPU load based on + * the current and target load values. + * + * \param[in] cpul: Pointer to the CPUL instance. + * \return Returns CPUL_E_OK on success, otherwise an error code. + */ +int cpul_task(CPUL *cpul); + +#endif diff --git a/source/06_performance/unitt.c b/source/06_performance/unitt.c new file mode 100644 index 0000000..e6c954e --- /dev/null +++ b/source/06_performance/unitt.c @@ -0,0 +1,306 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file unitt.c + * \unit unitt + * \brief This is a simple unit test module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#include "unitt.h" + +/** + * \brief Assert that a condition is true. + * + * This function checks if the given condition is true. If it is false, + * it outputs an assertion failure message and returns a failure code. + * + * \param[in] condition: The condition to evaluate. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_true(int condition, const char* message) +{ + if (!condition) + { + fprintf(stderr, "Assertion Failed: %s\n", message); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that a condition is false. + * + * This function checks if the given condition is false. If it is true, + * it outputs an assertion failure message and returns a failure code. + * + * \param[in] condition: The condition to evaluate. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_false(int condition, const char* message) +{ + if (condition) + { + fprintf(stderr, "Assertion Failed: %s\n", message); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that two integers are equal. + * + * This function checks whether the expected and actual values are equal. + * If they are not equal, it outputs an assertion failure message with + * both values and returns a failure code. + * + * \param[in] expected: The expected value. + * \param[in] actual: The actual value. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_equal(int expected, int actual, const char* message) +{ + if (expected != actual) + { + fprintf(stderr, "Assertion Failed: %s (Expected: %d, Actual: %d)\n", message, expected, actual); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that two integers are not equal. + * + * This function checks whether the expected and actual values are not equal. + * If they are equal, it outputs an assertion failure message and returns a failure code. + * + * \param[in] expected: The expected value. + * \param[in] actual: The actual value. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_nequal(int expected, int actual, const char* message) +{ + if (expected == actual) + { + fprintf(stderr, "Assertion Failed: %s (Expected not equal to Actual)\n", message); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that a pointer is NULL. + * + * This function checks whether the given pointer is NULL. If it is not NULL, + * it outputs an assertion failure message with the pointer's value and returns a failure code. + * + * \param[in] pointer: The pointer to evaluate. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_null(void* pointer, const char* message) +{ + if (pointer != NULL) + { + fprintf(stderr, "Assertion Failed: %s (Expected NULL, Actual: %p)\n", message, pointer); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that a pointer is not NULL. + * + * This function checks whether the given pointer is not NULL. If it is NULL, + * it outputs an assertion failure message and returns a failure code. + * + * \param[in] pointer: The pointer to evaluate. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_nnull(void* pointer, const char* message) +{ + if (pointer == NULL) + { + fprintf(stderr, "Assertion Failed: %s (Expected non-NULL, Actual: NULL)\n", message); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that two floats are approximately equal. + * + * This function checks whether the expected and actual float values are approximately equal + * within a given epsilon range. If they are not, it outputs an assertion failure message + * with both values and returns a failure code. + * + * \param[in] expected: The expected float value. + * \param[in] actual: The actual float value. + * \param[in] epsilon: The acceptable difference between the two values. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_float(float expected, float actual, float epsilon, const char* message) +{ + if (fabs(expected - actual) > epsilon) + { + fprintf(stderr, "Assertion Failed: %s (Expected: %.6f, Actual: %.6f)\n", message, expected, actual); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Assert that two strings are equal. + * + * This function checks whether the expected and actual strings are equal. + * If they are not equal, it outputs an assertion failure message with both strings + * and returns a failure code. + * + * \param[in] expected: The expected string. + * \param[in] actual: The actual string. + * \param[in] message: The message to display if the assertion fails. + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL. + */ +int unitt_det_string(const char* expected, const char* actual, const char* message) +{ + if (strcmp(expected, actual) != 0) + { + fprintf(stderr, "Assertion Failed: %s (Expected: '%s', Actual: '%s')\n", message, expected, actual); + return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +/** + * \brief Handle a test failure. + * + * This function is called when a test fails. It outputs the name of the failed test. + * + * \param[in] name: The name of the failed test. + * \return Returns UNITT_E_OK. + */ +int unitt_fail_handle(const char* name) +{ + printf("Failure in test: %s\n", name); + return UNITT_E_OK; +} + +/** + * \brief Execute a test suite. + * + * This function runs all the test cases within the provided test suites. + * It measures the execution time for each test and outputs a summary report. + * + * \param[in] suites: Array of test suites to execute. + * \param[in] count: Number of test suites in the array. + * \param[in] failcb: Callback function to handle test failures. + * \param[in] specific: Specific test name to execute (NULL for all). + * \param[in] filename: Output filename for results (NULL for stdout). + * \return none. + */ +void unitt_execute(UNITT* suites, uint32_t count, unitt_failcb_t failcb, const char* specific, const char* filename) +{ + UNITT* suite = NULL; + UNITT_TCASE* tcase = NULL; + uint64_t cstart = 0, cend = 0; // Record the start and end time of the test + + FILE* output = stdout; // Default output to standard output + if (filename != NULL) + { + output = fopen(filename, "w"); + if (output == NULL) + { + perror("Failed to open output file"); + return; + } + } + + // Iterate over each test suite + for (int i = 0; i < count; i++) + { + suite = &suites[i]; + + fprintf(output, "Running test suite: %s\n", suite->name); + + // Iterate over each test case + for (int j = 0; j < suite->count; j++) + { + tcase = &suite->tests[j]; + + if (specific && strcmp(tcase->name, specific) != 0) + { + continue; // Skip non-matching tests + } + + // Execute setup function before the test + if (tcase->setup) tcase->setup(); + + // Record start time + if (suite->clock) cstart = suite->clock(); + + // Execute test function + if (UNITT_E_OK == tcase->func()) + { + tcase->passed++; + } + else + { + if (failcb) failcb(tcase->name); + } + + // Record end time + if (suite->clock) cend = suite->clock(); + + // Accumulate the time taken for the test + if (suite->clock) tcase->time += (cend - cstart); + + // Execute teardown function after the test + if (tcase->teardown) tcase->teardown(); + + tcase->tested++; + } + } + + // Output summary of the tests + for (int i = 0; i < count; i++) + { + suite = &suites[i]; + + fprintf(output, "Test suite `%s` report: \r\n", suite->name); + + // Iterate over each test case + for (int j = 0; j < suite->count; j++) + { + tcase = &suite->tests[j]; + + fprintf(output, "[%s] Summary: tested %u, passed %u, time %llu us.\r\n", + tcase->name, + tcase->tested, + tcase->passed, + tcase->time + ); + } + } + + if (filename != NULL) + { + fclose(output); + } +} \ No newline at end of file diff --git a/source/06_performance/unitt.h b/source/06_performance/unitt.h new file mode 100644 index 0000000..86183f1 --- /dev/null +++ b/source/06_performance/unitt.h @@ -0,0 +1,184 @@ +/********************************************************************************************************* + * ------------------------------------------------------------------------------------------------------ + * file description + * ------------------------------------------------------------------------------------------------------ + * \file unitt.h + * \unit unitt + * \brief This is a simple unit test module for C language + * \author Lamdonn + * \version v1.0.0 + * \license GPL-2.0 + * \copyright Copyright (C) 2023 Lamdonn. + ********************************************************************************************************/ +#ifndef __unitt_H +#define __unitt_H + +#include +#include +#include +#include +#include +#include + +/* Version infomation */ +#define UNITT_V_MAJOR 0 +#define UNITT_V_MINOR 1 +#define UNITT_V_PATcH 0 + +// Type definition for a clock function +typedef uint64_t (*unitt_clock_t)(); + +// Type definition for a test function +typedef int (*unitt_func_t)(); + +// Type definition for a setup function before the test +typedef int (*unitt_setup_t)(); + +// Type definition for a teardown function after the test +typedef int (*unitt_teardown_t)(); + +// Type definition for a failure callback function +typedef int (*unitt_failcb_t)(const char* name); + +// Type definition for a random input generation function +typedef int (*unitt_randin_t)(); + +/** + * \brief Structure representing a test case + */ +typedef struct +{ + const char* name; ///< Name of the test + unitt_func_t func; ///< Pointer to the test function + unitt_setup_t setup; ///< Pointer to the setup function + unitt_teardown_t teardown; ///< Pointer to the teardown function + unitt_randin_t random_input; ///< Pointer to the random input generation function + uint32_t tested; ///< Count of tests executed + uint32_t passed; ///< Count of tests passed + uint64_t time; ///< Total time taken for the test +} UNITT_TCASE; + +/** + * \brief Structure representing a test suite + */ +typedef struct +{ + const char* name; ///< Name of the test suite + UNITT_TCASE* tests; ///< Array of test cases + uint32_t count; ///< Number of test cases + unitt_clock_t clock; ///< Pointer to the clock function for measuring time +} UNITT; + +#define UNITT_E_OK (0) // Success return code +#define UNITT_E_FAIL (-1) // Failure return code + +/** + * \brief Assert that a condition is true + * \param[in] condition: The condition to evaluate + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_true(int condition, const char* message); + +/** + * \brief Assert that a condition is false + * \param[in] condition: The condition to evaluate + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_false(int condition, const char* message); + +/** + * \brief Assert that two integers are equal + * \param[in] expected: The expected value + * \param[in] actual: The actual value + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_equal(int expected, int actual, const char* message); + +/** + * \brief Assert that two integers are not equal + * \param[in] expected: The expected value + * \param[in] actual: The actual value + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_nequal(int expected, int actual, const char* message); + +/** + * \brief Assert that a pointer is NULL + * \param[in] pointer: The pointer to evaluate + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_null(void* pointer, const char* message); + +/** + * \brief Assert that a pointer is not NULL + * \param[in] pointer: The pointer to evaluate + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_nnull(void* pointer, const char* message); + +/** + * \brief Assert that two floats are approximately equal + * \param[in] expected: The expected float value + * \param[in] actual: The actual float value + * \param[in] epsilon: The acceptable difference between the two values + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_float(float expected, float actual, float epsilon, const char* message); + +/** + * \brief Assert that two strings are equal + * \param[in] expected: The expected string + * \param[in] actual: The actual string + * \param[in] message: The message to display if the assertion fails + * \return Returns UNITT_E_OK if the assertion passes, otherwise UNITT_E_FAIL + */ +int unitt_det_string(const char* expected, const char* actual, const char* message); + +/** + * \brief Handle a test failure + * \param[in] name: The name of the failed test + * \return Returns UNITT_E_OK + */ +int unitt_fail_handle(const char* name); + +/** + * \brief Execute a test suite + * \param[in] suites: Array of test suites to execute + * \param[in] count: Number of test suites in the array + * \param[in] failcb: Callback function to handle test failures + * \param[in] specific: Specific test name to execute (NULL for all) + * \param[in] filename: Output filename for results (NULL for stdout) + * \return none + */ +void unitt_execute(UNITT* suites, uint32_t count, unitt_failcb_t failcb, const char* specific, const char* filename); + +/** + * \brief Macro to define a test case + * \param name: Name of the test case + */ +#define UNITT_TCASE(name) { #name, name, NULL, NULL, NULL, 0, 0, 0 } + +/** + * \brief Macro to execute a set of test cases + * \param suites: Array of test cases to execute + */ +#define UNITT_EXE(suites) unitt_execute((suites), sizeof(suites) / sizeof(suites[0]), unitt_fail_handle, 0, 0) + +/** + * \brief Macro to execute a set of test cases with additional parameters + * \param suites: Array of test cases to execute + * \param count: Number of test cases + * \param mode: Execution mode + * \param specific: Specific test name to execute + * \param output: Output filename for results + */ +#define UNITT_EXE2(suites, count, mode, specific, output) unitt_execute(suites, count, unitt_fail_handle, specific, output) + +#endif // __unit_H diff --git a/test/test.mk b/test/test.mk index ff21f6a..6e1ea54 100644 --- a/test/test.mk +++ b/test/test.mk @@ -45,6 +45,11 @@ TEST_INC = # TEST_SRC += $(TESTSPACE)/test_sList.c # TEST_SRC += $(TESTSPACE)/test_dList.c # TEST_SRC += $(TESTSPACE)/test_cQueue.c -TEST_SRC += $(TESTSPACE)/test_intl.c +# TEST_SRC += $(TESTSPACE)/test_intl.c +# TEST_SRC += $(TESTSPACE)/test_ramt.c +# TEST_SRC += $(TESTSPACE)/test_cpul.c +# TEST_SRC += $(TESTSPACE)/test_date.c +TEST_SRC += $(TESTSPACE)/test_unitt.c + export TEST_SRC TEST_INC diff --git a/test/test_cpul.c b/test/test_cpul.c new file mode 100644 index 0000000..2be8e4f --- /dev/null +++ b/test/test_cpul.c @@ -0,0 +1,200 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "init.h" +#include "cpul.h" + +#define CORE_NUM_MAX 32 +#define LINE_BUFFER_SIZE 1024 + +/** +* Structure for recording CPU counters in stat +*/ +typedef struct { + uint64_t user; /**< Time spent in user mode */ + uint64_t nice; /**< Time spent in low-priority user mode */ + uint64_t system; /**< Time spent in system mode */ + uint64_t idle; /**< Time spent waiting for tasks */ + uint64_t iowait; /**< Time spent waiting for I/O to complete */ + uint64_t irq; /**< Time spent processing interrupts */ + uint64_t softirq; /**< Time spent processing soft interrupts */ + uint64_t steal; /**< Time spent by other OS in virtual environment */ + uint64_t guest; /**< Time spent running guest OS */ + uint64_t guest_nice; /**< Time spent running low priority guest OS */ +} cputime_t; + +static uint16_t loadTable[CORE_NUM_MAX] = {0}; + +static cputime_t read_stat(int coreid) +{ + cputime_t work; + FILE *file; + char line[LINE_BUFFER_SIZE]; + + file = fopen("/proc/stat", "rb"); + if (file == NULL) { + } + + if (fgets(line, sizeof(line), file) == NULL) { + goto error; + } + + if (sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &work.user, + &work.nice, + &work.system, + &work.idle, + &work.iowait, + &work.irq, + &work.softirq, + &work.steal, + &work.guest, + &work.guest_nice) < 4) { + goto error; + } + + if (coreid > 0) + { + int i; + + for (i = 0; i < coreid; i++) + { + if (fgets(line, sizeof(line), file) == NULL) + { + goto error; + } + + if (sscanf(line, "cpu%*u %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &work.user, + &work.nice, + &work.system, + &work.idle, + &work.iowait, + &work.irq, + &work.softirq, + &work.steal, + &work.guest, + &work.guest_nice) < 4) + { + goto error; + } + } + } + +error: + fclose(file); + return work; +} + +void *loadupdate_entry(void *ptr) +{ + const int coreNum = *(int *)ptr; + cputime_t before[coreNum], after[coreNum], diff[coreNum]; + int i = 0; + + while(1) + { + /* Calcul real time load */ + for (i = 0; i < coreNum; i++) before[i] = read_stat(i); + usleep(1000000); + for (i = 0; i < coreNum; i++) after[i] = read_stat(i); + + for (i = 0; i < coreNum; i++) + { + if (after[i].user > before[i].user && after[i].idle > before[i].idle) + { + diff[i].user = after[i].user - before[i].user; + diff[i].idle = after[i].idle - before[i].idle; + loadTable[i] = (uint16_t)(((float)(diff[i].user) / (float)(diff[i].user + diff[i].idle)) * 10000); + } + else + { + loadTable[i] = 0; + } + + // printf("[core%d] load %d\r\n", i, loadTable[i]); + } + } +} + +uint16_t cpul_raw(uint8_t coreid) +{ + if (coreid >= CORE_NUM_MAX) return 0xFFFF; + return (uint16_t)(loadTable[coreid]); +} + +void *loadgen_entry(void *ptr) +{ + #define PERIOD 10 + const int coreid = *(int *)ptr; + CPUL cpul; + int ret = 0; + uint32_t count = 0; + uint16_t load = 0; + + cpul.coreid = coreid; + cpul.resolution = 10; + cpul.raw = cpul_raw; + ret = cpul_init(&cpul); + + ret = cpul_set(&cpul, 5000); + + while(1) + { + count += PERIOD; + if (count >= 25200000) count = 0; + + if (count % 1000 == 0) + { + ret = cpul_get(&cpul, &load); + printf("cpul_get<%d> %2d.%02d%%, %d, %d\r\n", coreid, (uint16_t)(load / 100), load % 100, cpul.ctrl.tload, cpul.ctrl.refine); + } + + cpul_task(&cpul); + usleep(1000 * PERIOD); + } +} + +static void test(void) +{ + int num_cpus = sysconf(_SC_NPROCESSORS_CONF); + pthread_t thread_update, thread_gen[num_cpus]; + int coreid[num_cpus]; + int ret; + + printf("Number of CPUs: %d\n", num_cpus); + + ret = pthread_create(&thread_update, NULL, &loadupdate_entry, &num_cpus); + if (ret != 0) { + printf("pthread_create failed!\n"); + } + + for (int i = 0; i < num_cpus; i++) + { + coreid[i] = i; + ret = pthread_create(&thread_gen[i], NULL, &loadgen_entry, &coreid[i]); + if (ret != 0) { + printf("pthread_create failed!\n"); + } + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(i, &cpuset); + sched_setaffinity(thread_gen[i], sizeof(cpu_set_t), &cpuset); + } + + pthread_join(thread_update, NULL); + for (int i = 0; i < num_cpus; i++) + { + pthread_join(thread_gen[i], NULL); + } +} +init_export_app(test); diff --git a/test/test_date.c b/test/test_date.c new file mode 100644 index 0000000..29c4463 --- /dev/null +++ b/test/test_date.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include "init.h" +#include "date.h" + +#if 0 +static int century_days(int century) +{ + int days = 0; + int year = (century - 1) * 100 + 1; + + for (int i = 0; i < 100; i++) + { + days += date_year_days(year + i); + } + + return days; +} + +static int thousand2_days(int base) +{ + int days = 0; + + for (int i = 0; i < 2000; i++) + { + days += date_year_days(base + i); + } + + return days; +} + +static int thousand3_days(int base) +{ + int days = 0; + int century = (base / 100) + 1; + + for (int i = 0; i < 20; i++) + { + // days += century_days(century + i); + days += date_century_days(century + i); + } + + return days; +} +#endif + +static void test(void) +{ + printf("month days %d\r\n", date_month_days(2024, 11)); + printf("date_isleap %d\r\n", date_isleap(1582)); + // printf("date_current_days %d\r\n", date_current_days(DATE(1,1,1))); + // printf("date_current_days %d\r\n", date_current_days(DATE(2000,12,31))); + // printf("date_current_days %d\r\n", date_current_days(DATE(2001,1,1))); + // printf("date_current_days %d\r\n", date_current_days(DATE(2024,11,9))); + printf("date_get_week %d\r\n", date_get_week(DATE(2024,11,11))); + + printf("date_diff_days %d\r\n", date_diff_days(DATE(2018,3,14), DATE(2024,11,10))); + + // DATE date = date_from_days(date_current_days(DATE(2024,11,30))); + DATE date = date_offset(DATE(2024,11,30), -1); + + printf("%d.%d.%d\r\n", date.year,date.month,date.day); + + date_show(1998,7); + date_show(2024,11); + date_show(2224,11); +} +init_export_app(test); diff --git a/test/test_ramt.c b/test/test_ramt.c new file mode 100644 index 0000000..78b0261 --- /dev/null +++ b/test/test_ramt.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include "init.h" +#include "tool.h" +#include "ramt.h" +#include "kern.h" + +#define TASK_PERIOD 5 // ms + +static uint8_t buffer[128]; +static RAMT ramt_object; + +static void test_task(void) +{ + static int count = 0; + + count += TASK_PERIOD; + + ramt_task(&ramt_object); + + if (count % 1000 == 0) + { + printf("result %08X\r\n", ramt_result(&ramt_object)); + } +} + +static void test_ramt(void) +{ + task_t task; + + printf("ramt test!\r\n"); + + ramt_object.base = (void *)buffer; + ramt_object.size = sizeof(buffer); + ramt_init(&ramt_object); + + ramt_start(&ramt_object, RAMT_MODE_NORMAL, 0xFFFFFFFF); + + task = task_create(TASK_PERIOD, test_task); + printf("task <%d>\r\n", task); +} +init_export_app(test_ramt); diff --git a/test/test_unitt.c b/test/test_unitt.c new file mode 100644 index 0000000..dcb070e --- /dev/null +++ b/test/test_unitt.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include "init.h" +#include "unitt.h" +#include "kern.h" + +#if 0 +#ifdef _WIN32 +#include +#include // -lPsapi +#else +#include +#include +#endif + +void get_memory_usage(int* resident_set_size, int* virtual_memory_size) +{ +#ifdef _WIN32 + PROCESS_MEMORY_COUNTERS pmc; + if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { + *resident_set_size = pmc.WorkingSetSize / 1024; // 转换为KB + *virtual_memory_size = pmc.PagefileUsage / 1024; // 转换为KB + } else { + *resident_set_size = 0; + *virtual_memory_size = 0; + } +#else + FILE* file = fopen("/proc/self/statm", "r"); + if (file) { + fscanf(file, "%d %d", resident_set_size, virtual_memory_size); + fclose(file); + } else { + *resident_set_size = 0; + *virtual_memory_size = 0; + } +#endif +} +#endif + +#define SINGLE_TCOUNT 1000 + +uint64_t unitt_clock(void) +{ + struct timeval mstime; + uint64_t us = 0; + gettimeofday(&mstime, NULL); + us = mstime.tv_sec * 1000000 + mstime.tv_usec; + return us; +} + +// 计算两个整数的和 +int unit_add(int a, int b) +{ + return a + b; +} + +// 计算两个整数的差 +int unit_subtract(int a, int b) +{ + return a - b; +} + +// 计算两个整数的乘积 +int unit_multiply(int a, int b) +{ + return a * b; +} + +// 计算两个整数的商 +float unit_divide(int a, int b) +{ + if (b == 0) + { + return 0; // 简单处理,真实应用中应更严格处理 + } + return (float)a / (float)b; +} + +// 测试前的初始化函数 +int setup() +{ + // 初始化代码(如果需要) + return 0; +} + +// 测试后的清理函数 +int teardown() +{ + // 清理代码(如果需要) + return 0; +} + +// 随机输入生成函数 +int random_input() +{ + return rand() % 100; // 生成0到99之间的随机整数 +} + +// 测试加法函数,使用随机输入 +int test_add() +{ + // 进行10次随机测试 + for (int i = 0; i < SINGLE_TCOUNT; i++) + { + int a = random_input(); + int b = random_input(); + if (UNITT_E_FAIL == unitt_det_equal(unit_add(a, b), a + b, "Random addition failed")) return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +// 测试减法函数,使用随机输入 +int test_subtract() +{ + // 进行10次随机测试 + for (int i = 0; i < SINGLE_TCOUNT; i++) + { + int a = random_input(); + int b = random_input(); + if (UNITT_E_FAIL == unitt_det_equal(unit_subtract(a, b), a - b, "Random subtraction failed")) return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +// 测试乘法函数,使用随机输入 +int test_multiply() +{ + // 进行10次随机测试 + for (int i = 0; i < SINGLE_TCOUNT; i++) + { + int a = random_input(); + int b = random_input(); + if (UNITT_E_FAIL == unitt_det_equal(unit_multiply(a, b), a * b, "Random multiplication failed")) return UNITT_E_FAIL; + } + + return UNITT_E_OK; +} + +// 测试除法函数,使用随机输入 +int test_divide() +{ + // 进行10次随机测试 + for (int i = 0; i < SINGLE_TCOUNT; i++) + { + int a = random_input(); + int b = random_input(); + if (b != 0) + { + if (UNITT_E_FAIL == unitt_det_float(unit_divide(a, b), (float)a / (float)b, 0.00001, "Random division failed")) return UNITT_E_FAIL; + } + } + + return UNITT_E_OK; +} + +void unit_main() +{ + static UNITT_TCASE math_tests[] = { + UNITT_TCASE(test_add), + UNITT_TCASE(test_subtract), + UNITT_TCASE(test_multiply), + UNITT_TCASE(test_divide), + }; + + static UNITT suites[] = { + { "Math Suite", math_tests, sizeof(math_tests) / sizeof(math_tests[0]) , unitt_clock }, + }; + + UNITT_EXE(suites); +} + +static void test(void) +{ + srand((unsigned int)time(NULL)); // 初始化随机数种子 + + // unit_main(); + printf("create task %d\r\n", task_create(1000, unit_main)); +} +init_export_app(test);