diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index b00dc139..41581988 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -24,26 +24,9 @@ jobs: # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. # todo: add windows-latest matrix: - os: [ubuntu-latest] - build_type: [Release, Debug] - c_compiler: [gcc, clang, cl] - include: - # - os: windows-latest - # c_compiler: cl - # cpp_compiler: cl - - os: ubuntu-latest - c_compiler: gcc - cpp_compiler: g++ - - os: ubuntu-latest - c_compiler: clang - cpp_compiler: clang++ - exclude: - # - os: windows-latest - # c_compiler: gcc - # - os: windows-latest - # c_compiler: clang - - os: ubuntu-latest - c_compiler: cl + os: [ubuntu-latest, ubuntu-22.04-arm] + build_type: [Release, Debug, Tsan] + c_compiler: [gcc, clang] steps: - uses: actions/checkout@v4 @@ -60,7 +43,6 @@ jobs: # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: > cmake -B ${{ steps.strings.outputs.build-output-dir }} - -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S ${{ github.workspace }} diff --git a/doc/developer.md b/doc/developer.md new file mode 100644 index 00000000..13b22413 --- /dev/null +++ b/doc/developer.md @@ -0,0 +1,10 @@ +# TEST + +## tsan +to enable tsan test, build cmd: + +```bash +# cd repo root +cmake -DCMAKE_BUILD_TYPE=Tsan -B build && cmake --build build -j8 +ctest --test-dir build +``` \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh index 4b3e3f83..210c624b 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -92,6 +92,32 @@ test_simple() eval "$asan_pre $bin_dir/test_dzlog_conf -f $conf_dir/test_consumer_static_file_single.conf -n 10" } +fifo() +{ + output="output" + target="cf64f2750cd39abc18d86cb152d0ec77" + testcnt=350000 + eval "$asan_pre $bin_dir/fifo_test -s 0x800000 -e 16 -n $testcnt > $output" + ret=$? + if [[ "$ret" -ne 0 ]]; then + echo "failed to test ${FUNCNAME[0]}" + return 1 + fi + # rm -f $target ; touch $target + # i=0 + # while [ "$i" -lt "$testcnt" ]; do + # echo "data $i" >> $target + # i=$(($i + 1)) + # done + md5output=$(md5sum $output | awk '{ print $1 }') + if [ "$md5output" = "$target" ]; then + echo "match, $md5output == $target" + return 0 + fi + echo "failed, $md5output != $target" + return 1 +} + while getopts "t:a::v" opt; do case $opt in t) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e5451c4b..f031a704 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,3 +66,12 @@ install(FILES COMPONENT zlog DESTINATION include ) + +if (CMAKE_BUILD_TYPE STREQUAL "Tsan") + if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(zlog PRIVATE -fsanitize=thread -g -O1 -fno-omit-frame-pointer) + target_link_options(zlog PRIVATE -fsanitize=thread) + target_compile_options(zlog-chk-conf PRIVATE -fsanitize=thread -g -O1 -fno-omit-frame-pointer) + target_link_options(zlog-chk-conf PRIVATE -fsanitize=thread) + endif() +endif() diff --git a/src/fifo.c b/src/fifo.c index 60152a67..f7b2171f 100644 --- a/src/fifo.c +++ b/src/fifo.c @@ -138,7 +138,7 @@ struct msg_head *fifo_reserve(struct fifo *fifo, unsigned int size) struct msg_head *head = (struct msg_head *)&fifo->data[old_in & fifo->mask]; head->total_size = total_size; - atomic_load_explicit(&head->flags, memory_order_relaxed); + atomic_store_explicit(&head->flags, MSG_HEAD_FLAG_RESERVED, memory_order_relaxed); atomic_store_explicit(&fifo->in, old_in + total_size, memory_order_release); return head; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cbdab0b1..8db0d4ba 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,10 +28,13 @@ set(not_auto_add_test test_longlog test_multithread test_dzlog_conf + fifo_test + test_pipe ) if (CMAKE_BUILD_TYPE STREQUAL "Release") list(REMOVE_ITEM SRCS ./test_buf.c) # release does not export buf functions + list(REMOVE_ITEM SRCS ./fifo_test.c) # release does not export buf functions endif() # single command test @@ -44,6 +47,13 @@ foreach (test_src ${SRCS}) add_executable("${test_name}" "${test_src}") target_link_libraries(${test_name} zlog) + if (CMAKE_BUILD_TYPE STREQUAL "Tsan") + if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(${test_name} PRIVATE -fsanitize=thread -g -O1 -fno-omit-frame-pointer) + target_link_options(${test_name} PRIVATE -fsanitize=thread) + endif() + endif() + list(FIND not_auto_add_test ${test_name} not_auto_test) if (not_auto_test EQUAL -1) add_test("${test_name}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test_name}") @@ -69,8 +79,13 @@ find_program(MD5_EXECUTABLE NAMES md5sum REQUIRED) set(script_test consumer_static_file_single varify_static_file_single + fifo ) +if (CMAKE_BUILD_TYPE STREQUAL "Release") + list(REMOVE_ITEM script_test fifo) +endif() + foreach (case ${script_test}) set(TEST_WORKING_DIR "${CMAKE_BINARY_DIR}/Testing/Temporary/${case}") file(MAKE_DIRECTORY ${TEST_WORKING_DIR}) diff --git a/test/fifo_test.c b/test/fifo_test.c new file mode 100644 index 00000000..cfd803cb --- /dev/null +++ b/test/fifo_test.c @@ -0,0 +1,139 @@ +/* Copyright (c) Hardy Simpson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fifo.h" +#include "misc.h" + +struct conf { + unsigned test_cnt; + unsigned per_data_size; + struct fifo *fifo; +}; + +static void *thread_func(void *ptr) +{ + struct conf *conf = ptr; + for (unsigned i = 0; i < conf->test_cnt; i++) { + struct msg_head *head = NULL; + while (head == NULL) { + head = fifo_reserve(conf->fifo, conf->per_data_size - msg_head_size()); + } + unsigned *val = (unsigned *)head->data; + *val = i; + fifo_commit(conf->fifo, head); + } + + return NULL; +} + +int main(int argc, char **argv) +{ + static const struct option long_options[] = { + {"fifo_size", required_argument, 0, 's'}, + {"element_size", required_argument, 0, 'e'}, + {"count", required_argument, 0, 'n'}, + {0, 0, 0, 0}, + }; + + unsigned required_fifo_size = 0; + unsigned required_element_size = 0; + unsigned test_cnt = 0; + + for (int opt = -1, option_index = 0; + ((opt = getopt_long(argc, argv, "s:e:n:", long_options, &option_index)) != -1);) { + switch (opt) { + case 's': + required_fifo_size = strtol(optarg, NULL, 16); + break; + case 'e': + required_element_size = atoi(optarg); + break; + case 'n': + test_cnt = atoi(optarg); + break; + case '?': // Unknown option + fprintf(stderr, "Usage: %s [-f ] [arguments...]\n", argv[0]); + exit(EXIT_FAILURE); + } + } + + if (required_fifo_size == 0) { + fprintf(stderr, "invalid fifo size %u", required_fifo_size); + exit(EXIT_FAILURE); + } + if (required_element_size == 0) { + fprintf(stderr, "invalid element size %u", required_element_size); + exit(EXIT_FAILURE); + } + if (test_cnt == 0) { + fprintf(stderr, "invalid test cnt %u", test_cnt); + exit(EXIT_FAILURE); + } + + int ret = 0; + + struct fifo *fifo = fifo_create(required_fifo_size); + if (fifo == NULL) { + fprintf(stderr, "failed to create fifo\n"); + goto exit; + } + fprintf(stderr, "create fifo size %lx\n", fifo_size(fifo)); + + unsigned per_data_size = required_element_size; + struct conf conf = { + .fifo = fifo, + .per_data_size = per_data_size, + .test_cnt = test_cnt, + }; + + fprintf(stderr, "test cnt: %u, per_data_size %u\n", conf.test_cnt, per_data_size); + fprintf(stderr, "==== start ====\n"); + + pthread_t tids; + assert(!pthread_create(&tids, NULL, thread_func, &conf)); + + for (unsigned i = 0; i < conf.test_cnt; i++) { + struct msg_head *head = NULL; + + while (head == NULL) { + head = fifo_peek(fifo); + if (head == NULL) { + continue; + } + unsigned flag = atomic_load_explicit(&head->flags, memory_order_acquire); + if (flag == MSG_HEAD_FLAG_RESERVED) { + head = NULL; + } + } + unsigned *val = (unsigned *)head->data; + printf("data %u\n", *val); + fifo_out(fifo, head); + } + + assert(!pthread_join(tids, NULL)); + fifo_destroy(fifo); + +exit: + return ret; +} diff --git a/test/test_init.c b/test/test_init.c index 69ff3fa8..c6d0ade1 100644 --- a/test/test_init.c +++ b/test/test_init.c @@ -39,7 +39,6 @@ int main(int argc, char** argv) return -1; } zlog_info(zc, "before update"); - sleep(1); rc = zlog_reload("test_init.2.conf"); if (rc) { printf("update fail\n"); @@ -48,7 +47,6 @@ int main(int argc, char** argv) zlog_profile(); zlog_fini(); - sleep(1); zlog_init("test_init.conf"); zc = zlog_get_category("my_cat"); if (!zc) { diff --git a/test/test_pipe2.c b/test/test_pipe2.c new file mode 100644 index 00000000..408416aa --- /dev/null +++ b/test/test_pipe2.c @@ -0,0 +1,40 @@ +/* Copyright (c) Hardy Simpson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "zlog.h" +#include + +int main(int argc, char **argv) +{ + int rc; + zlog_category_t *zc; + + rc = zlog_init("test_pipe2.conf"); + if (rc) { + printf("init failed\n"); + return -1; + } + + zc = zlog_get_category("my_cat"); + if (!zc) { + printf("get cat fail\n"); + zlog_fini(); + return -2; + } + + zlog_info(zc, "hello, zlog"); + zlog_fini(); + return 0; +} diff --git a/test/test_pipe2.conf b/test/test_pipe2.conf new file mode 100644 index 00000000..1fa4d251 --- /dev/null +++ b/test/test_pipe2.conf @@ -0,0 +1,4 @@ +[formats] +simple = "%m%n" +[rules] +my_cat.* |cat -A diff --git a/test/test_prompt.c b/test/test_prompt.c index f18cd097..be4908d2 100644 --- a/test/test_prompt.c +++ b/test/test_prompt.c @@ -41,7 +41,7 @@ int main(int argc, char** argv) for (int i =0; i<15;i++){ zlog_info(pzc, "prompt>"); - usleep(300000); + usleep(30000); if (!(i % 3)) zlog_debug(zc, "dummy log entry %d", i); if (!(i % 5)) diff --git a/test/test_tmp.c b/test/test_tmp.c index 01d7769a..4d90e310 100755 --- a/test/test_tmp.c +++ b/test/test_tmp.c @@ -38,8 +38,6 @@ int main(int argc, char** argv) zlog_debug(zc, "%s%d", "hello, zlog ", 1); zlog_info(zc, "hello, zlog 2"); - sleep(1); - zlog_info(zc, "hello, zlog 3"); zlog_debug(zc, "hello, zlog 4");