cachetest:Tools for testing cache and uncacheable

Summary:
  A tool is provided to test the case of data correctness after cache flush. It requires an uncacheable offset to check whether the uncacheable address is consistent with the data in the buffer after calling up_dcache_flush.

Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
This commit is contained in:
chenrun1 2024-02-28 15:06:07 +08:00 committed by Xiang Xiao
parent 1d9f045068
commit 09ec04760f
4 changed files with 349 additions and 0 deletions

29
testing/cachetest/Kconfig Normal file
View File

@ -0,0 +1,29 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config TESTING_CACHETEST
tristate "Cache Test"
default n
---help---
Enable a simple Cache test.
if TESTING_CACHETEST
config TESTING_CACHETEST_PROGNAME
string "Program name"
default "cachetest"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config TESTING_CACHETEST_PRIORITY
int "Cache test task priority"
default 100
config TESTING_CACHETEST_STACKSIZE
int "Cache test stack size"
default DEFAULT_TASK_STACKSIZE
endif

View File

@ -0,0 +1,23 @@
############################################################################
# apps/testing/cachetest/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_CACHETEST),)
CONFIGURED_APPS += $(APPDIR)/testing/cachetest
endif

View File

@ -0,0 +1,32 @@
############################################################################
# apps/testing/cachetest/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
# Cache test
PROGNAME = $(CONFIG_TESTING_CACHETEST_PROGNAME)
PRIORITY = $(CONFIG_TESTING_CACHETEST_PRIORITY)
STACKSIZE = $(CONFIG_TESTING_CACHETEST_STACKSIZE)
MODULE = $(CONFIG_TESTING_CACHETEST)
MAINSRC = cachetest_main.c
include $(APPDIR)/Application.mk

View File

@ -0,0 +1,265 @@
/****************************************************************************
* apps/testing/cachetest/cachetest_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 <nuttx/config.h>
#include <stdio.h>
#include <syslog.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define CACHETEST_PREFIX "CACHE Test: "
#define OPTARG_TO_VALUE(value, type, base) \
do \
{ \
FAR char *ptr; \
value = (type)strtoul(optarg, &ptr, base); \
if (*ptr != '\0') \
{ \
syslog(LOG_ERR, CACHETEST_PREFIX "Parameter error -%c %s\n", ch, \
optarg); \
cahcetest_show_usage(); \
} \
} while (0)
/****************************************************************************
* Private Types
****************************************************************************/
struct cachetest_s
{
FAR char *wbuf;
FAR char *rbuf;
FAR char *waddr;
uintptr_t offset;
size_t size;
int repeat_num;
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: cahcetest_show_usage
****************************************************************************/
static void cahcetest_show_usage(void)
{
printf("\nUsage: %s -s [buffer-size] -f [offset] -n [repeat-number]\n",
CONFIG_TESTING_CACHETEST_PROGNAME);
printf("\nWhere:\n");
printf(" -s [buffer-size] number of memory alloc for buffer"
"(in bytes). [Default Size: 1MB] \n");
printf(" -f [offset] offset to uncacheble address [Default: 0]\n");
printf(" -n [repeat-number] number of repetitions"
" [default value: unlimited].\n");
exit(EXIT_FAILURE);
}
/****************************************************************************
* Name: cachetest_parse_commandline
****************************************************************************/
static void cachetest_parse_commandline(int argc, FAR char **argv,
FAR struct cachetest_s *info)
{
int ch;
/* Default size: 1M */
memset(info, 0, sizeof(struct cachetest_s));
info->size = 1024 * 1024;
while ((ch = getopt(argc, argv, "s::n::f::i")) != ERROR)
{
switch (ch)
{
case 's':
OPTARG_TO_VALUE(info->size, size_t, 10);
break;
case 'n':
OPTARG_TO_VALUE(info->repeat_num, int, 10);
break;
case 'f':
OPTARG_TO_VALUE(info->offset, uintptr_t, 16);
break;
case '?':
cahcetest_show_usage();
break;
}
}
info->wbuf = zalloc(info->size);
if (info->wbuf == NULL)
{
syslog(LOG_ERR, CACHETEST_PREFIX "Alloc memory for info->wbuf"
"failed:%d\n",
ENOMEM);
exit(EXIT_FAILURE);
}
info->rbuf = zalloc(info->size);
if (info->rbuf == NULL)
{
free(info->wbuf);
syslog(LOG_ERR, CACHETEST_PREFIX "Alloc memory for info->rbuf"
"failed:%d\n",
ENOMEM);
exit(EXIT_FAILURE);
}
info->waddr = zalloc(info->size);
if (info->waddr == NULL)
{
free(info->wbuf);
free(info->rbuf);
syslog(LOG_ERR, CACHETEST_PREFIX "Alloc memory for info->waddr"
"failed:%d\n",
ENOMEM);
exit(EXIT_FAILURE);
}
syslog(LOG_INFO, CACHETEST_PREFIX "waddr:%p, uncacheble addr start:%p,"
"size:%u\n", info->waddr,
(FAR char *)((uintptr_t)info->waddr | info->offset), info->size);
}
/****************************************************************************
* Name: cachetest_teardown
****************************************************************************/
static void cachetest_teardown(FAR struct cachetest_s *info)
{
free(info->waddr);
free(info->rbuf);
free(info->wbuf);
}
/****************************************************************************
* Name: cachetest_randchar
****************************************************************************/
static inline char cachetest_randchar(void)
{
int value = random() % 63;
if (value == 0)
{
return '0';
}
else if (value <= 10)
{
return value + '0' - 1;
}
else if (value <= 36)
{
return value + 'a' - 11;
}
else
{
return value + 'A' - 37;
}
}
/****************************************************************************
* Name: cachetest_randcontext
****************************************************************************/
static void cachetest_randcontext(uint32_t size, FAR void *input)
{
/* Construct a buffer here and fill it with random characters */
int i;
FAR char *tmp;
tmp = input;
for (i = 0; i < size - 1; i++)
{
tmp[i] = cachetest_randchar();
}
tmp[i] = '\0';
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: cachetest_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
FAR char *ptr;
struct cachetest_s info;
/* Prepare parameters */
cachetest_parse_commandline(argc, argv, &info);
/* If there is no set number of times to repeat, it will loop continuously
* by default.
*/
for (int loop = 1; ((!info.repeat_num) || loop <= info.repeat_num);
loop++)
{
cachetest_randcontext(info.size, info.wbuf);
/* Get uncacheable address */
ptr = (FAR char *)((uintptr_t)info.waddr | info.offset);
memcpy(info.waddr, info.wbuf, info.size);
up_flush_dcache((uintptr_t)info.waddr, (uintptr_t)info.waddr +
info.size);
for (size_t i = 0; i < info.size; i++)
{
info.rbuf[i] = *ptr++;
}
if (memcmp(info.wbuf, info.rbuf, info.size) != 0)
{
syslog(LOG_ERR, CACHETEST_PREFIX "comparison failed!\n");
}
else
{
syslog(LOG_INFO, CACHETEST_PREFIX "comparsion success!\n");
}
/* To prevent tasks from being occupied all the time, switch
* scheduling through usleep.
*/
usleep(1);
}
cachetest_teardown(&info);
return 0;
}