From 7ab1f2a9573d74e704cc674296f49ecf855f423a Mon Sep 17 00:00:00 2001 From: XinStellaris Date: Tue, 14 Mar 2023 21:08:25 +0800 Subject: [PATCH] Add Arch-specific libc test case. Signed-off-by: XinStellaris --- testing/arch_libc/Kconfig | 38 ++++ testing/arch_libc/Make.defs | 23 +++ testing/arch_libc/Makefile | 34 ++++ testing/arch_libc/README.md | 13 ++ testing/arch_libc/arch_libc_test_main.c | 250 ++++++++++++++++++++++++ 5 files changed, 358 insertions(+) create mode 100644 testing/arch_libc/Kconfig create mode 100644 testing/arch_libc/Make.defs create mode 100644 testing/arch_libc/Makefile create mode 100644 testing/arch_libc/README.md create mode 100644 testing/arch_libc/arch_libc_test_main.c diff --git a/testing/arch_libc/Kconfig b/testing/arch_libc/Kconfig new file mode 100644 index 000000000..c8bdfa9f2 --- /dev/null +++ b/testing/arch_libc/Kconfig @@ -0,0 +1,38 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config TESTING_ARCH_LIBC + tristate "arch-specific libc function test" + default n + depends on ARCH_TOOLCHAIN_GNU + ---help--- + Enable the arch libc test + +if TESTING_ARCH_LIBC + +config TESTING_ARCH_LIBC_STRCPY + bool "test strcpy" + default n + +config TESTING_ARCH_LIBC_PROGNAME + string "Program name" + default "arch_libctest" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config TESTING_ARCH_LIBC_PRIORITY + int "arch libc test priority" + default 100 + +config TESTING_ARCH_LIBC_STACKSIZE + int "arch libc test stack size" + default DEFAULT_TASK_STACKSIZE + +config TESTING_ARCH_LIBC_VERBOSE + bool "Verbose output" + default n + +endif diff --git a/testing/arch_libc/Make.defs b/testing/arch_libc/Make.defs new file mode 100644 index 000000000..4b4d205a1 --- /dev/null +++ b/testing/arch_libc/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/testing/arch_libc/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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. +# +############################################################################ + +ifneq ($(CONFIG_TESTING_ARCH_LIBC),) +CONFIGURED_APPS += $(APPDIR)/testing/arch_libc +endif diff --git a/testing/arch_libc/Makefile b/testing/arch_libc/Makefile new file mode 100644 index 000000000..bd376459d --- /dev/null +++ b/testing/arch_libc/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/testing/arch_libc/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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 $(APPDIR)/Make.defs + +# test application info + +PROGNAME = $(CONFIG_TESTING_ARCH_LIBC_PROGNAME) +PRIORITY = $(CONFIG_TESTING_ARCH_LIBC_PRIORITY) +STACKSIZE = $(CONFIG_TESTING_ARCH_LIBC_STACKSIZE) +MODULE = $(CONFIG_TESTING_ARCH_LIBC) + +# arch libc test + +MAINSRC = arch_libc_test_main.c + +include $(APPDIR)/Application.mk diff --git a/testing/arch_libc/README.md b/testing/arch_libc/README.md new file mode 100644 index 000000000..c45f062c7 --- /dev/null +++ b/testing/arch_libc/README.md @@ -0,0 +1,13 @@ +# Testing / `arch_libc` Arch-specific libc Test + +This is a test for arch-specific libc function. Arch-specific libc functions are often implemented in +assembly language, here is the test for these functions. The test focuses on key features in assembly +language, including aligned access, speed, callee saved register check and so on. +Currently, the test only contains a subset of possible arch-specific libc functions. You are welcomed +to put more cases here. + +- `CONFIG_TESTING_ARCH_LIBC` – Enable the test. +- `CONFIG_TESTING_ARCH_LIBC_XXXXX` – Enable test for function XXXXX. + +EXAMPLE + arch_libc - Run the test. diff --git a/testing/arch_libc/arch_libc_test_main.c b/testing/arch_libc/arch_libc_test_main.c new file mode 100644 index 000000000..d9585b3ce --- /dev/null +++ b/testing/arch_libc/arch_libc_test_main.c @@ -0,0 +1,250 @@ +/**************************************************************************** + * apps/testing/arch_libc/arch_libc_test_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifdef CONFIG_TESTING_ARCH_LIBC_STRCPY +# define TEST_MAX_STRING_LEN 128 +# define TEST_SHORT_SRC_LEN 50 +# define TEST_LONG_SRC_LEN 128 +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_TESTING_ARCH_LIBC_STRCPY +static char g_test_src_str[TEST_MAX_STRING_LEN]; +static char g_test_dst_str[TEST_MAX_STRING_LEN]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_TESTING_ARCH_LIBC_STRCPY + +/**************************************************************************** + * Name: arch_libc_test_strcpy + ****************************************************************************/ + +void init_short_test_str(int dst_offset, int src_offset) +{ + int off; + + memset(g_test_src_str, '\0', sizeof(g_test_src_str)); + memset(g_test_dst_str, '\0', sizeof(g_test_dst_str)); + + for (off = 0; off < TEST_SHORT_SRC_LEN; off++) + { + g_test_src_str[off + src_offset] = '0' + off % 10; + } +} + +/**************************************************************************** + * Name: arch_libc_test_strcpy_offset + ****************************************************************************/ + +int arch_libc_test_strcpy_offset(int dst_offset, int src_offset) +{ + int off; + FAR char *dest; + FAR char *src; + FAR char *result_str; + bool pass = true; + + init_short_test_str(dst_offset, src_offset); + dest = g_test_dst_str + dst_offset; + src = g_test_src_str + src_offset; + result_str = strcpy(dest, src); + + /* check strcpy data */ + + for (off = 0; off < TEST_SHORT_SRC_LEN; off++) + { + if (result_str[off] != '0' + off % 10) + { + pass = false; + printf("dest copied data error, index %d\n", off); + } + + if (src[off] != '0' + off % 10) + { + pass = false; + printf("src data error, index %d\n", off); + } + } + + for (off = TEST_SHORT_SRC_LEN; off < TEST_MAX_STRING_LEN - dst_offset; + off++) + { + if (result_str[off] != '\0') + { + pass = false; + printf("dest tailing zero error, index %d\n", off); + } + } + + for (off = TEST_SHORT_SRC_LEN; off < TEST_MAX_STRING_LEN - src_offset; + off++) + { + if (src[off] != '\0') + { + pass = false; + printf("src tailing zero error, index %d\n", off); + } + } + + /* strcpy shouln't change arch_libc_test_strcpy's local variable */ + + if (dest != (g_test_dst_str + dst_offset) || + src != (g_test_src_str + src_offset)) + { + pass = false; + printf("local var changed after calling strcpy\n"); + } + + if (!pass) + { + printf("Test Failed at dst/src offset [%d, %d]\n", dst_offset, + src_offset); + return -1; + } + + return 0; +} + +/**************************************************************************** + * Name: arch_libc_test_strcpy + ****************************************************************************/ + +int arch_libc_test_strcpy(void) +{ + int dest_off; + int src_off; + int ret = 0; + + for (dest_off = 0; dest_off <= 4; dest_off++) + { + for (src_off = 0; src_off <= 4; src_off++) + { + if (arch_libc_test_strcpy_offset(dest_off, src_off) != 0) + { + ret = -1; + } + } + } + + if (ret != 0) + { + printf("arch_libc_test_strcpy Test Failed\n"); + } + else + { + printf("arch_libc_test_strcpy Test Passed\n"); + } + + return ret; +} + +/**************************************************************************** + * Name: arch_libc_strcpy_speed_offset + ****************************************************************************/ + +uint32_t arch_libc_strcpy_speed_offset(int dst_offset, int src_offset) +{ + FAR char *dest; + FAR char *src; + uint32_t start; + uint32_t end; + + init_short_test_str(dst_offset, src_offset); + dest = g_test_dst_str + dst_offset; + src = g_test_src_str + src_offset; + start = up_perf_gettime(); + strcpy(dest, src); + end = up_perf_gettime(); + + return end - start; +} + +/**************************************************************************** + * Name: arch_libc_strcpy_speed + ****************************************************************************/ + +int arch_libc_strcpy_speed(void) +{ + int dest_off; + int src_off; + uint32_t cycles = 0; + + for (dest_off = 0; dest_off <= 4; dest_off++) + { + for (src_off = 0; src_off <= 4; src_off++) + { + cycles += arch_libc_strcpy_speed_offset(dest_off, src_off); + } + } + + printf("strcpy total(run 25 times) cpu cycles %" PRIu32 "\n", cycles); + printf("strcpy average cpu cycles %" PRIu32 "\n", cycles / 25); + + return 0; +} + +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ +#ifdef CONFIG_TESTING_ARCH_LIBC_STRCPY + arch_libc_test_strcpy(); + arch_libc_strcpy_speed(); +#endif + + return 0; +} +