diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a0138f --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +!.gitignore +*.o +out_* +buildout +build +output +install.sh +make.sh + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..771d974 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,34 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +cmake_minimum_required(VERSION 3.5.1) +project(prd_utils C) +set(CMAKE_C_STANDARD 99) + +# Add fpic +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# Board Selection +if (${BOARD_NAME} MATCHES "light*") + set(BOARD_NAME "light") + include(cmake/board_light.cmake) +else () + message(FATAL_ERROR, "No BOARD_NAME") +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -g") +set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") + +include(cmake/show_cmake_param.cmake) + + +# Add include dirs for all sub modules +include_directories(${PROJECT_BINARY_DIR}) +include_directories(${PROJECT_SOURCE_DIR}/include) + +add_subdirectory(platform/${BOARD_NAME}) +add_subdirectory(utils) +add_subdirectory(test) + +install(FILES ${INSTALL_HEAD_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/README.en.md b/README.en.md deleted file mode 100644 index c7e4662..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# prd-utils - -#### Description -product produce utilities - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index e553b17..c558d5c 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,20 @@ -# prd-utils +# Comments +This is utilities for product produce process, including: +- utils for set/get/clean Key-Value -#### 介绍 -product produce utilities +# How to get the code +- git clone git@gitlab.alibaba-inc.com:thead-linux/prd_utils.git -#### 软件架构 -软件架构说明 +# How to build +1. export PATH=riscv-toolchain-2.2.8/bin:$PATH +2. mkdir build +3. cd buildout +4. cmake ../ -DBOARD_NAME="light" -DCMAKE_INSTALL_BINDIR=bin -DCMAKE_INSTALL_LIBDIR=lib -DCMAKE_INSTALL_INCLUDEDIR=include -DCMAKE_C_COMPILER=gcc +5. make - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +# Description of each directories +- cmake/: The cmake files for build. +- include/: The header files. +- platform/: Different platform implementation code directories. +- test/: The test cases. +- utils/: The utils using in console. diff --git a/cmake/board_light.cmake b/cmake/board_light.cmake new file mode 100644 index 0000000..c72f113 --- /dev/null +++ b/cmake/board_light.cmake @@ -0,0 +1,6 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +SET(CMAKE_C_COMPILER riscv64-linux-gcc) +SET(CMAKE_CXX_COMPILER riscv64-linux-c++) diff --git a/cmake/custom_macros.cmake b/cmake/custom_macros.cmake new file mode 100644 index 0000000..123fa05 --- /dev/null +++ b/cmake/custom_macros.cmake @@ -0,0 +1,11 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +macro(BuildNormalProgram sourceName) + set(TargetName ${sourceName}) + set(target_src ${sourceName}.c) + add_executable(${TargetName} ${target_src}) + target_link_libraries(${TargetName} ${linkLibs}) +endmacro(BuildNormalProgram) + diff --git a/cmake/show_cmake_param.cmake b/cmake/show_cmake_param.cmake new file mode 100644 index 0000000..c7c6d63 --- /dev/null +++ b/cmake/show_cmake_param.cmake @@ -0,0 +1,19 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +message("") +message("=== Show cmake system paramerters ===") +message(STATUS "PROJECT_NAME = ${PROJECT_NAME}") +message(STATUS "PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}") +message(STATUS "PROJECT_BINARY_DIR = ${PROJECT_BINARY_DIR}") +message(STATUS "CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}") +message(STATUS "CMAKE_SYSTEM_PROCESSOR = ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "CMAKE_SYSTEM = ${CMAKE_SYSTEM}") +message(STATUS "CMAKE_C_COMPILER = ${CMAKE_C_COMPILER}") +message(STATUS "CMAKE_C_FLAGS = ${CMAKE_C_FLAGS}") +message(STATUS "CMAKE_SHARED_LINKER_FLAGS = ${CMAKE_SHARED_LINKER_FLAGS}") +message(STATUS "BOARD_NAME = ${BOARD_NAME}") + +message(STATUS "CMAKE_INSTALL_LIBDIR = ${CMAKE_INSTALL_LIBDIR}") +message("") diff --git a/include/prd_utils_internal.h b/include/prd_utils_internal.h new file mode 100644 index 0000000..7a76d09 --- /dev/null +++ b/include/prd_utils_internal.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#ifndef PRD_UTILS_INTERNAL_H +#define PRD_UTILS_INTERNAL_H + +#include + +#define MKTAG_NEGA(e) (-(e)) + +#define LOG_COLOR_RED_YELLO_BACK "\033[1;31;43m" +#define LOG_COLOR_RED "\033[2;31;49m" +#define LOG_COLOR_YELLOW "\033[2;33;49m" +#define LOG_COLOR_GREEN "\033[2;32;49m" +#define LOG_COLOR_BLUE "\033[2;34;49m" +#define LOG_COLOR_GRAY "\033[1;30m" +#define LOG_COLOR_WHITE "\033[1;47;49m" +#define LOG_COLOR_RESET "\033[0m" + + +#define PRD_UTILS_LOG(fmt, args...) \ + do {printf("[%s():%d] ",__FUNCTION__, __LINE__); printf(fmt,##args);} while(0) + +#define PRD_UTILS_ASSERT(expr) \ + do { \ + if (!(expr)) { \ + printf(LOG_COLOR_RED \ + "\nASSERT failed at:\n"\ + " >File name: %s\n" \ + " >Function : %s\n" \ + " >Line No. : %d\n" \ + " >Condition: %s\n" \ + LOG_COLOR_RESET, \ + __FILE__,__FUNCTION__, __LINE__, #expr);\ + exit(-1); \ + } \ + } while(0) + + +#endif /* PRD_UTILS_INTERNAL_H */ diff --git a/include/prd_utils_kv.h b/include/prd_utils_kv.h new file mode 100644 index 0000000..bbcb80e --- /dev/null +++ b/include/prd_utils_kv.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#ifndef PRD_UTILS_KV_H +#define PRD_UTILS_KV_H + +#define PRD_UTILS_KEY_MAX_LENGTH 64 +#define PRD_UTILS_VAL_MAX_LENGTH 256 +#define PRD_UTILS_KV_MAX_COUNT 128 + +#define PRD_UTILS_KEY_NAME_ETH_ADDR "ethaddr" +#define PRD_UTILS_KEY_NAME_SN "sn" + +typedef enum { + PRD_UTILS_RESULT_OK = 0, + PRD_UTILS_RESULT_KV_INPUT_INVALID = -1, + PRD_UTILS_RESULT_KV_IO_FAILED = -2, + PRD_UTILS_RESULT_KV_NOT_EXIST = -3, +} prd_utils_result_e; + +// Notice: +// 1. input key CAN'T including space or other non-printable charater +// 2. input value CAN'T including any non-printable charater + +int prd_utils_get_kv(char *key, char **value); +int prd_utils_set_kv(char *key, char *value); +int prd_utils_clean_kv(char *key); + +#endif /* PRD_UTILS_KV_H */ diff --git a/platform/light/CMakeLists.txt b/platform/light/CMakeLists.txt new file mode 100644 index 0000000..deb38f5 --- /dev/null +++ b/platform/light/CMakeLists.txt @@ -0,0 +1,20 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +# include +INCLUDE_DIRECTORIES(./) + +SET(LIBSOURCE + prd_utils_kv_light.c + uboot_env_params.c +) + +ADD_LIBRARY(prd_utils SHARED ${LIBSOURCE}) + +INSTALL(DIRECTORY ./include/. DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +INSTALL(TARGETS prd_utils + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + diff --git a/platform/light/prd_utils_kv_light.c b/platform/light/prd_utils_kv_light.c new file mode 100644 index 0000000..682748b --- /dev/null +++ b/platform/light/prd_utils_kv_light.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#include +#include + +#include +#include + +#include "uboot_env_params.h" + +#define CHECK_KEY_VALID(key) \ + do { \ + if (key == NULL || strlen(key) >= PRD_UTILS_KEY_MAX_LENGTH) \ + { \ + PRD_UTILS_LOG("key is NULL or key len > %d\n", PRD_UTILS_KEY_MAX_LENGTH); \ + return PRD_UTILS_RESULT_KV_INPUT_INVALID; \ + } \ + } while (0) + +#define CHECK_VAL_VALID(val) \ + do { \ + if (val == NULL || strlen(val) >= PRD_UTILS_VAL_MAX_LENGTH) \ + { \ + PRD_UTILS_LOG("val is NULL or val len > %d\n", PRD_UTILS_VAL_MAX_LENGTH); \ + return PRD_UTILS_RESULT_KV_INPUT_INVALID; \ + } \ + } while (0) + + +int prd_utils_get_kv(char *key, char **value) +{ + CHECK_KEY_VALID(key); + + return light_uboot_get_env(key, value); +} + +int prd_utils_set_kv(char *key, char *value) +{ + CHECK_KEY_VALID(key); + CHECK_VAL_VALID(value); + + return light_uboot_set_env(key, value); +} + +int prd_utils_clean_kv(char *key) +{ + CHECK_KEY_VALID(key); + + return light_uboot_clean_env(key); +} + diff --git a/platform/light/uboot_env_params.c b/platform/light/uboot_env_params.c new file mode 100644 index 0000000..59fa0f8 --- /dev/null +++ b/platform/light/uboot_env_params.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#include +#include +#include + +#include +#include + +#include "uboot_env_params.h" +static char g_result[PRD_UTILS_VAL_MAX_LENGTH] = ""; + +static int execmd_fetch_result_string(const char *cmd, char *result) +{ + char buffer[PRD_UTILS_VAL_MAX_LENGTH]; + + FILE *pipe = popen(cmd, "r"); + if (pipe == NULL) + { + return -1; + } + + while(!feof(pipe)) + { + if(fgets(buffer, PRD_UTILS_VAL_MAX_LENGTH, pipe)) + { + strcat(result, buffer); + if(strlen(result) >= PRD_UTILS_VAL_MAX_LENGTH) + break; + } + } + + pclose(pipe); + return 0; +} + +int light_uboot_get_env(const char *key, char **value) +{ + char cmd[128 + PRD_UTILS_KEY_MAX_LENGTH] =""; + memset(g_result, 0, sizeof(g_result)); + + snprintf(cmd, sizeof(cmd), + "fw_printenv | grep '%s=' | awk -F '=' '{print $2}' | tr -d '\n' '\r'", key); + + if (execmd_fetch_result_string(cmd, g_result) == 0) + { + *value = g_result; + if (strlen(*value) == 0) + { + //PRD_UTILS_LOG("light_uboot_get_env() failed, return enmpty value\n"); + return PRD_UTILS_RESULT_KV_NOT_EXIST; + } + + return PRD_UTILS_RESULT_OK; + } + else + { + *value = NULL; + //PRD_UTILS_LOG("light_uboot_get_env() failed\n"); + return PRD_UTILS_RESULT_KV_IO_FAILED; + } +} + +int light_uboot_set_env(const char *key, char *value) +{ + char cmd[128 + PRD_UTILS_KEY_MAX_LENGTH + PRD_UTILS_VAL_MAX_LENGTH] =""; + snprintf(cmd, sizeof(cmd), "fw_setenv %s '%s'", key, value); + + if (system(cmd) != 0) + { + PRD_UTILS_LOG("execute cmd='%s' failed\n", cmd); + return PRD_UTILS_RESULT_KV_IO_FAILED; + } + + return PRD_UTILS_RESULT_OK; +} + +int light_uboot_clean_env(const char *key) +{ + char cmd[128 + PRD_UTILS_KEY_MAX_LENGTH] = ""; + snprintf(cmd, sizeof(cmd), "fw_setenv %s", key); + + if (system(cmd) != 0) + { + PRD_UTILS_LOG("execute cmd='%s' failed\n", cmd); + return PRD_UTILS_RESULT_KV_IO_FAILED; + } + + return PRD_UTILS_RESULT_OK; +} + diff --git a/platform/light/uboot_env_params.h b/platform/light/uboot_env_params.h new file mode 100644 index 0000000..6e9baf9 --- /dev/null +++ b/platform/light/uboot_env_params.h @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#ifndef UBOOT_ENV_PARAMS_H +#define UBOOT_ENV_PARAMS_H + +int light_uboot_get_env(const char *key, char **value); +int light_uboot_set_env(const char *key, char *value); +int light_uboot_clean_env(const char *key); + +#endif /* UBOOT_ENV_PARAMS_H */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..0d31bdd --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +include(${PROJECT_SOURCE_DIR}/cmake/custom_macros.cmake) + +# Config all parameters for test cases below +set(linkLibs prd_utils) + +# test factory param +BuildNormalProgram(test_prd_utils_kv) + diff --git a/test/test_prd_utils_kv.c b/test/test_prd_utils_kv.c new file mode 100644 index 0000000..244775a --- /dev/null +++ b/test/test_prd_utils_kv.c @@ -0,0 +1,254 @@ + /* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define KV_OP_MAX_DURATION 100 // unit: ms + +static char test_key[] = "test_key"; +static char test_val[] = "test value with spaces"; + +static char max_length_key[PRD_UTILS_KEY_MAX_LENGTH] = + "12345678901234567890123456789012345678901234567890" \ + "1234567890123"; + +static char max_length_val[PRD_UTILS_VAL_MAX_LENGTH] = + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345"; + +typedef struct test_performance_records +{ + // unit: us + int normal_set; + int normal_get; + int normal_clean; + int max_len_set; + int max_len_get; + int max_len_clean; + + // tmp values + struct timeval tpstart; + struct timeval tpend; +} test_performance_records_t; + +static test_performance_records_t perf_records; + +#define GET_TIME_BEGIN() do { gettimeofday(&perf_records.tpstart, NULL); } while(0) +#define GET_TIME_RECORD(target) do { gettimeofday(&perf_records.tpend, NULL); \ + target = 1000000 * (perf_records.tpend.tv_sec - perf_records.tpstart.tv_sec) \ + + perf_records.tpend.tv_usec - perf_records.tpstart.tv_usec; \ + } while (0) + +static int test_prd_utils_set_kv() +{ + printf("Test: prd_utils_set_kv() start\n"); + + GET_TIME_BEGIN(); + PRD_UTILS_ASSERT(prd_utils_set_kv(test_key, test_val) == PRD_UTILS_RESULT_OK); + GET_TIME_RECORD(perf_records.normal_set); + + printf("Test: prd_utils_set_kv() pass\n\n"); + return 0; +} + +static int test_prd_utils_get_kv() +{ + char *get_val; + printf("Test: prd_utils_get_kv() start\n"); + + GET_TIME_BEGIN(); + PRD_UTILS_ASSERT(prd_utils_get_kv(test_key, &get_val) == PRD_UTILS_RESULT_OK); + GET_TIME_RECORD(perf_records.normal_get); + + PRD_UTILS_ASSERT(strncmp(test_val, get_val, PRD_UTILS_VAL_MAX_LENGTH) == 0); + + printf("Test: prd_utils_get_kv() pass\n\n"); + return 0; +} + +static int test_prd_utils_clean_kv() +{ + char *get_val; + printf("Test: prd_utils_clean_kv() start\n"); + + GET_TIME_BEGIN(); + PRD_UTILS_ASSERT(prd_utils_clean_kv(test_key) == PRD_UTILS_RESULT_OK); + GET_TIME_RECORD(perf_records.normal_clean); + + PRD_UTILS_ASSERT(prd_utils_get_kv(test_key, &get_val) == PRD_UTILS_RESULT_KV_NOT_EXIST); + + printf("Test: prd_utils_clean_kv() pass\n\n"); + return 0; +} + + +static int test_prd_utils_max_kv_value_length() +{ + char *get_val; + printf("Test: max value length(%u) start\n", PRD_UTILS_VAL_MAX_LENGTH); + + PRD_UTILS_ASSERT(strlen(max_length_val) == PRD_UTILS_VAL_MAX_LENGTH - 1); + + PRD_UTILS_ASSERT(prd_utils_set_kv(test_key, max_length_val) == PRD_UTILS_RESULT_OK); + PRD_UTILS_ASSERT(prd_utils_get_kv(test_key, &get_val) == PRD_UTILS_RESULT_OK); + PRD_UTILS_ASSERT(strncmp(max_length_val, get_val, PRD_UTILS_VAL_MAX_LENGTH) == 0); + + PRD_UTILS_ASSERT(prd_utils_clean_kv(test_key) == PRD_UTILS_RESULT_OK); + PRD_UTILS_ASSERT(prd_utils_get_kv(test_key, &get_val) == PRD_UTILS_RESULT_KV_NOT_EXIST); + + printf("Test: max value length(%u) pass\n\n", PRD_UTILS_VAL_MAX_LENGTH); + return 0; +} + +static int test_prd_utils_max_kv_key_length() +{ + char *get_val; + printf("Test: max key length(%u) start\n", PRD_UTILS_KEY_MAX_LENGTH); + + PRD_UTILS_ASSERT(strlen(max_length_key) == PRD_UTILS_KEY_MAX_LENGTH - 1); + + PRD_UTILS_ASSERT(prd_utils_set_kv(max_length_key, test_val) == PRD_UTILS_RESULT_OK); + PRD_UTILS_ASSERT(prd_utils_get_kv(max_length_key, &get_val) == PRD_UTILS_RESULT_OK); + PRD_UTILS_ASSERT(strncmp(test_val, get_val, PRD_UTILS_VAL_MAX_LENGTH) == 0); + + PRD_UTILS_ASSERT(prd_utils_clean_kv(max_length_key) == PRD_UTILS_RESULT_OK); + PRD_UTILS_ASSERT(prd_utils_get_kv(max_length_key, &get_val) == PRD_UTILS_RESULT_KV_NOT_EXIST); + + printf("Test: max key length(%u) pass\n\n", PRD_UTILS_KEY_MAX_LENGTH); + return 0; +} + +static int test_prd_utils_max_kv_capacity() +{ + char *get_val; + char test_key[PRD_UTILS_KEY_MAX_LENGTH]; + char test_val[PRD_UTILS_VAL_MAX_LENGTH]; + + printf("Test: max kv capacity(key_len=%u, val_len=%u, count=%u) start\n", + PRD_UTILS_KEY_MAX_LENGTH, PRD_UTILS_VAL_MAX_LENGTH, PRD_UTILS_KV_MAX_COUNT); + + const int test_loop_count = PRD_UTILS_KV_MAX_COUNT; + // set KVs + printf(" step1. testing set max kv(loop=%d):\n ", test_loop_count); + for (int i = 0; i < test_loop_count; i++) + { + //snprintf(test_key, PRD_UTILS_KEY_MAX_LENGTH, test_key_long_fmt, i); + snprintf(test_key, PRD_UTILS_KEY_MAX_LENGTH, + "12345678901234567890123456789012345678901234567890123456789_%03d", i); + + PRD_UTILS_ASSERT(strlen(test_key) == PRD_UTILS_KEY_MAX_LENGTH - 1); + + snprintf(test_val, PRD_UTILS_VAL_MAX_LENGTH, + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "1_%03d", i); + PRD_UTILS_ASSERT(strlen(test_val) == PRD_UTILS_VAL_MAX_LENGTH - 1); + + if (i == 0) GET_TIME_BEGIN(); + PRD_UTILS_ASSERT(prd_utils_set_kv(test_key, test_val) == PRD_UTILS_RESULT_OK); + if (i == 0) GET_TIME_RECORD(perf_records.max_len_set); + + printf("."); fflush(stdout); if (i % 64 == 63) printf("\n "); + } + + // get KVs and verify, clean + printf("step2. testing get max kv(loop=%d):\n ", test_loop_count); + for (int i = 0; i < test_loop_count; i++) + { + snprintf(test_key, PRD_UTILS_KEY_MAX_LENGTH, + "12345678901234567890123456789012345678901234567890123456789_%03d", i); + + snprintf(test_val, PRD_UTILS_VAL_MAX_LENGTH, + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "12345678901234567890123456789012345678901234567890" \ + "1_%03d", i); + + if (i == 0) GET_TIME_BEGIN(); + PRD_UTILS_ASSERT(prd_utils_get_kv(test_key, &get_val) == PRD_UTILS_RESULT_OK); + if (i == 0) GET_TIME_RECORD(perf_records.max_len_get); + + PRD_UTILS_ASSERT(strncmp(test_val, get_val, PRD_UTILS_VAL_MAX_LENGTH) == 0); + printf("."); fflush(stdout); if (i % 64 == 63) printf("\n "); + } + + // clean KVs + printf("step3. testing clean max kv(loop=%d):\n ", test_loop_count); + for (int i = 0; i < test_loop_count; i++) + { + snprintf(test_key, PRD_UTILS_KEY_MAX_LENGTH, + "12345678901234567890123456789012345678901234567890123456789_%03d", i); + + if (i == 0) GET_TIME_BEGIN(); + PRD_UTILS_ASSERT(prd_utils_clean_kv(test_key) == PRD_UTILS_RESULT_OK); + if (i == 0) GET_TIME_RECORD(perf_records.max_len_clean); + + PRD_UTILS_ASSERT(prd_utils_get_kv(test_key, &get_val) == PRD_UTILS_RESULT_KV_NOT_EXIST); + printf("."); fflush(stdout); if (i % 64 == 63) printf("\n "); + } + + printf("Test: max kv capacity(key_len=%u, val_len=%u, count=%u) pass\n\n", + PRD_UTILS_KEY_MAX_LENGTH, PRD_UTILS_VAL_MAX_LENGTH, PRD_UTILS_KV_MAX_COUNT); + + return 0; +} + +int main(int argc, char *argv[]) +{ + // test normal usage + PRD_UTILS_ASSERT(test_prd_utils_set_kv() == 0); + PRD_UTILS_ASSERT(test_prd_utils_get_kv() == 0); + PRD_UTILS_ASSERT(test_prd_utils_clean_kv() == 0); + + // test max length + PRD_UTILS_ASSERT(test_prd_utils_max_kv_value_length() == 0); + PRD_UTILS_ASSERT(test_prd_utils_max_kv_key_length() == 0); + + // test max capacity + PRD_UTILS_ASSERT(test_prd_utils_max_kv_capacity() == 0); + + // print performance + printf("==== prd_utils performance test results ====================\n"); + printf(" normal set_kv(key_len=%zu, val_len=%zu) cost %.3f ms\n", + strlen(test_key), strlen(test_val), (1.0 * perf_records.normal_set) / 1000); + printf(" normal get_kv(key_len=%zu, val_len=%zu) cost %.3f ms\n", + strlen(test_key), strlen(test_val), (1.0 * perf_records.normal_get) / 1000); + printf(" normal clean_kv(key_len=%zu, val_len=%zu) cost %.3f ms\n", + strlen(test_key), strlen(test_val), (1.0 * perf_records.normal_clean) / 1000); + + printf(" max_len set_kv(key_len=%u, val_len=%u) cost %.3f ms\n", + PRD_UTILS_KEY_MAX_LENGTH, PRD_UTILS_VAL_MAX_LENGTH, (1.0 * perf_records.max_len_set) / 1000); + printf(" max_len get_kv(key_len=%u, val_len=%u) cost %.3f ms\n", + PRD_UTILS_KEY_MAX_LENGTH, PRD_UTILS_VAL_MAX_LENGTH, (1.0 * perf_records.max_len_get) / 1000); + printf(" max_len clean_kv(key_len=%u, val_len=%u) cost %.3f ms\n", + PRD_UTILS_KEY_MAX_LENGTH, PRD_UTILS_VAL_MAX_LENGTH, (1.0 * perf_records.max_len_clean) / 1000); + printf("============================================================\n"); + + PRD_UTILS_ASSERT(perf_records.normal_set/1000 < KV_OP_MAX_DURATION && + perf_records.normal_get/1000 < KV_OP_MAX_DURATION && + perf_records.normal_clean/1000 < KV_OP_MAX_DURATION && + perf_records.max_len_set/1000 < KV_OP_MAX_DURATION && + perf_records.max_len_get/1000 < KV_OP_MAX_DURATION && + perf_records.max_len_clean/1000 < KV_OP_MAX_DURATION); + + printf(LOG_COLOR_GREEN "All KV tests PASSED\n" LOG_COLOR_RESET); + return 0; +} + diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 0000000..d93282c --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (C) 2023 Alibaba Group Holding Limited +# + +include(${PROJECT_SOURCE_DIR}/cmake/custom_macros.cmake) + +# Config all parameters for test cases below +set(linkLibs prd_utils) + +# test factory param +BuildNormalProgram(prd_utils_kv) + diff --git a/utils/prd_utils_kv.c b/utils/prd_utils_kv.c new file mode 100644 index 0000000..42c2417 --- /dev/null +++ b/utils/prd_utils_kv.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2023 Alibaba Group Holding Limited + */ + +#include +#include +#include +#include + +#include + +#define PROGRAM_NAME "prd_utils_kv" + +typedef struct +{ + int op_code; /* 0: set, 1:get; 2: clean */ + char key[PRD_UTILS_KEY_MAX_LENGTH]; + char val[PRD_UTILS_VAL_MAX_LENGTH]; +} cmd_params_s; + +static const char *shortopts = "hs:g:c:"; +static const struct option long_options[] = +{ + {"help", no_argument, 0, 'h'}, + {"SetParam", required_argument, 0, 's'}, + {"GetParam", required_argument, 0, 'g'}, + {"CleanParam", required_argument, 0, 'c'}, + {0, 0, 0, 0 } // Act as end of option +}; + +static void usage(char *program_name) +{ + printf("Usage: %s [OPTION]\n", program_name); + printf(" -h, --help display this help and exit\n"); + printf(" -s, --SetParam set param, for example: %s -s sn=123456abcde\n", program_name); + printf(" -g, --GetParam get param, for example: %s -g sn\n", program_name); + printf(" -c, --CleanParam clean param, for example: %s -c sn\n", program_name); +} + +static int parse_params(int argc, char *argv[], cmd_params_s *params) +{ + int c; + int option_index = 0; + int option_count = 0; + + char *program_name = PROGRAM_NAME; + + char *equal_sign; + int pos; + + while ((c = getopt_long(argc, argv, shortopts, long_options, &option_index)) != -1) + { + switch (c) + { + case 'h': + usage(program_name); + exit(0); + case 's': + params->op_code = 0; + equal_sign = strchr(optarg, '='); + if (equal_sign == NULL) + { + printf("command is invalid, please flow:\n"); + usage(program_name); + exit(-1); + } + pos = equal_sign - optarg; + strncpy(params->key, optarg, pos); + strncpy(params->val, optarg + pos + 1, strlen(optarg) - pos); + option_count++; + break; + case 'g': + params->op_code = 1; + sscanf(optarg, "%s", params->key); + option_count++; + break; + case 'c': + params->op_code = 2; + sscanf(optarg, "%s", params->key); + option_count++; + break; + default: + printf("Not supported opt:'%c'\n", c); + return -1; + } + } + + return option_count; +} + +int main(int argc, char *argv[]) +{ + int ret; + char *val; + + cmd_params_s cmd_params; + memset(&cmd_params, 0, sizeof(cmd_params)); + int option_count = parse_params(argc, argv, &cmd_params); + if (option_count == 0) + { + usage(PROGRAM_NAME); + exit(0); + } + + switch (cmd_params.op_code) + { + case 0: // set + ret = prd_utils_set_kv(cmd_params.key, cmd_params.val); + printf("set '%s'='%s' %s\n", cmd_params.key, cmd_params.val, (ret == 0) ? "OK" : "failed"); + break; + case 1: // get + ret = prd_utils_get_kv(cmd_params.key, &val); + if (ret != 0) + { + printf("get sys param '%s' failed\n", cmd_params.key); + return ret; + } + printf("Got sys param '%s'='%s'\n", cmd_params.key, val); + break; + case 2: // clean; + ret = prd_utils_clean_kv(cmd_params.key); + printf("clean sys param '%s' %s\n", cmd_params.key, (ret == 0) ? "OK" : "failed"); + break; + } + + return 0; +} +