Browse Source

Linux_SDK_V1.1.2

thead_admin 1 year ago
parent
commit
d6e05608be

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+!.gitignore
+*.o
+out_*
+buildout
+build
+output
+install.sh
+make.sh
+

+ 34 - 0
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})

+ 0 - 36
README.en.md

@@ -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/)

+ 20 - 37
README.md

@@ -1,37 +1,20 @@
-# prd-utils
-
-#### 介绍
-product produce utilities
-
-#### 软件架构
-软件架构说明
-
-
-#### 安装教程
-
-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/)
+# Comments
+This is utilities for product produce process, including:
+- utils for set/get/clean Key-Value
+
+# 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
+
+# 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.

+ 6 - 0
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++)

+ 11 - 0
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)
+

+ 19 - 0
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("")

+ 41 - 0
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 <errno.h>
+
+#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 */

+ 30 - 0
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 */

+ 20 - 0
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})
+

+ 53 - 0
platform/light/prd_utils_kv_light.c

@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 Alibaba Group Holding Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <prd_utils_kv.h>
+#include <prd_utils_internal.h>
+
+#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);
+}
+

+ 93 - 0
platform/light/uboot_env_params.c

@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2023 Alibaba Group Holding Limited
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <prd_utils_kv.h>
+#include <prd_utils_internal.h>
+
+#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;
+}
+

+ 12 - 0
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 */

+ 12 - 0
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)
+

+ 254 - 0
test/test_prd_utils_kv.c

@@ -0,0 +1,254 @@
+ /*
+ * Copyright (C) 2023 Alibaba Group Holding Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/time.h>
+
+#include <prd_utils_kv.h>
+#include <prd_utils_internal.h>
+
+#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;
+}
+

+ 12 - 0
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)
+

+ 128 - 0
utils/prd_utils_kv.c

@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2023 Alibaba Group Holding Limited
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <prd_utils_kv.h>
+
+#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;
+}
+