system/cachespeed:Tools for testing cache-related speed.
Signed-off-by: crafcat <110923103+crafcat7@users.noreply.github.com>
This commit is contained in:
parent
8e8d461590
commit
0e0ac0656b
30
system/cachespeed/Kconfig
Normal file
30
system/cachespeed/Kconfig
Normal file
@ -0,0 +1,30 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config SYSTEM_CACHESPEED
|
||||
tristate "CACHE Speed Test"
|
||||
default n
|
||||
---help---
|
||||
Enable a simple CACHE speed test.
|
||||
|
||||
if SYSTEM_CACHESPEED
|
||||
|
||||
config SYSTEM_CACHESPEED_PROGNAME
|
||||
string "Program name"
|
||||
default "cachespeed"
|
||||
---help---
|
||||
This is the name of the program that will be used when the NSH ELF
|
||||
program is installed.
|
||||
|
||||
config SYSTEM_CACHESPEED_PRIORITY
|
||||
int "CACHE speed test task priority"
|
||||
default 100
|
||||
|
||||
config SYSTEM_CACHESPEED_STACKSIZE
|
||||
int "CACHE speed test stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
endif
|
||||
|
23
system/cachespeed/Make.defs
Normal file
23
system/cachespeed/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/system/cachespeed/Make.def
|
||||
#
|
||||
# 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_SYSTEM_CACHESPEED),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/cachespeed
|
||||
endif
|
32
system/cachespeed/Makefile
Normal file
32
system/cachespeed/Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
############################################################################
|
||||
# apps/system/cachespeed/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 speed test
|
||||
|
||||
PROGNAME = $(CONFIG_SYSTEM_CACHESPEED_PROGNAME)
|
||||
PRIORITY = $(CONFIG_SYSTEM_CACHESPEED_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_SYSTEM_CACHESPEED_STACKSIZE)
|
||||
MODULE = $(CONFIG_SYSTEM_CACHESPEED)
|
||||
|
||||
MAINSRC = cachespeed_main.c
|
||||
|
||||
include $(APPDIR)/Application.mk
|
368
system/cachespeed/cachespeed_main.c
Normal file
368
system/cachespeed/cachespeed_main.c
Normal file
@ -0,0 +1,368 @@
|
||||
/****************************************************************************
|
||||
* apps/system/cachespeed/cachespeed_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/arch.h>
|
||||
#include <nuttx/cache.h>
|
||||
#include <nuttx/irq.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define CACHESPEED_PREFIX "CACHE Speed: "
|
||||
|
||||
#define GET_VALUE(value, type) \
|
||||
do \
|
||||
{ \
|
||||
FAR char *ptr; \
|
||||
value = (type)strtoul(optarg, &ptr, 0); \
|
||||
if (*ptr != '\0') \
|
||||
{ \
|
||||
printf(CACHESPEED_PREFIX "Parameter error: -%c %s\n", option, optarg); \
|
||||
show_usage(argv[0], EXIT_FAILURE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct cachespeed_s
|
||||
{
|
||||
FAR void *begin;
|
||||
size_t memset_size;
|
||||
uint32_t repeat_num;
|
||||
size_t opt_size;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: show_usage
|
||||
****************************************************************************/
|
||||
|
||||
static void show_usage(FAR const char *progname, int exitcode)
|
||||
{
|
||||
printf("\nUsage: %s -b <address> -o <operation size>"
|
||||
" -s <memset size>[262144] -n <repeat number>[100] \n",
|
||||
progname);
|
||||
printf("\nWhere:\n");
|
||||
printf(" -b <hex-address> begin memset address.\n");
|
||||
printf(" -o <operation size> The size of the operation.\n");
|
||||
printf(" -s <memset size> Execute memset size (in bytes)."
|
||||
" [default value: 262144].\n");
|
||||
printf(" -n <repeat num> number of repetitions"
|
||||
" [default value: 1000].\n");
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: parse_commandline
|
||||
****************************************************************************/
|
||||
|
||||
static void parse_commandline(int argc, FAR char **argv,
|
||||
FAR struct cachespeed_s *info)
|
||||
{
|
||||
int option;
|
||||
|
||||
memset(info, 0, sizeof(struct cachespeed_s));
|
||||
info->repeat_num = 1000;
|
||||
info->memset_size = 262144;
|
||||
|
||||
while ((option = getopt(argc, argv, "b:o:s:n:")) != ERROR)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case 'b':
|
||||
GET_VALUE(info->begin, void *);
|
||||
break;
|
||||
case 'o':
|
||||
GET_VALUE(info->opt_size, size_t);
|
||||
break;
|
||||
case 's':
|
||||
GET_VALUE(info->memset_size, size_t);
|
||||
break;
|
||||
case 'n':
|
||||
GET_VALUE(info->repeat_num, uint32_t);
|
||||
if (info->repeat_num == 0)
|
||||
{
|
||||
printf(CACHESPEED_PREFIX "<repeat number> must > 0\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
printf(CACHESPEED_PREFIX "Unknown option: %c\n", optopt);
|
||||
show_usage(argv[0], EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->opt_size == 0 || info->begin == 0)
|
||||
{
|
||||
printf(CACHESPEED_PREFIX "Missing required arguments\n");
|
||||
show_usage(argv[0], EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: get_perf_time
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t get_perf_time(void)
|
||||
{
|
||||
return up_perf_gettime();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: get_time_elaps
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t get_time_elaps(uint32_t prev_time)
|
||||
{
|
||||
return get_perf_time() - prev_time;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: print_result
|
||||
****************************************************************************/
|
||||
|
||||
static void print_result(FAR const char *name, size_t bytes,
|
||||
uint32_t cost_time)
|
||||
{
|
||||
uint32_t rate;
|
||||
struct timespec ts;
|
||||
|
||||
/* Converted to ms */
|
||||
|
||||
up_perf_convert(cost_time, &ts);
|
||||
cost_time = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
|
||||
if (cost_time == 0)
|
||||
{
|
||||
printf(CACHESPEED_PREFIX
|
||||
"Time-consuming is too short\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* rate = (bytes / 1024) / (cost_time / 1000) */
|
||||
|
||||
rate = (uint64_t)bytes * 1000 / cost_time / 1024;
|
||||
printf(CACHESPEED_PREFIX
|
||||
"%s cost = %" PRIu32 " ms\t[Rate: %" PRIu32 "KB/s]\n",
|
||||
name, cost_time, rate);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: dcache_speed_test
|
||||
****************************************************************************/
|
||||
|
||||
static void dcache_speed_test(FAR void *begin, size_t memset_size,
|
||||
size_t opt_size, uint32_t repeat_cnt)
|
||||
{
|
||||
size_t total_size = memset_size * repeat_cnt;
|
||||
uint32_t invalidate_cost_time;
|
||||
uint32_t clean_cost_time;
|
||||
uint32_t flush_cost_time;
|
||||
uint32_t cnt;
|
||||
uint32_t pt;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Initialize a variable */
|
||||
|
||||
invalidate_cost_time = 0;
|
||||
clean_cost_time = 0;
|
||||
flush_cost_time = 0;
|
||||
|
||||
/* Accumulate the time to get the total time */
|
||||
|
||||
printf("______dcache performance______\n");
|
||||
|
||||
printf("______do all operation______\n");
|
||||
flags = enter_critical_section();
|
||||
for (cnt = 0; cnt < repeat_cnt; cnt++)
|
||||
{
|
||||
uint32_t start_time;
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_clean_dcache_all();
|
||||
clean_cost_time += get_time_elaps(start_time);
|
||||
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_flush_dcache_all();
|
||||
flush_cost_time += get_time_elaps(start_time);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
print_result("clean dcache():\t", total_size, clean_cost_time);
|
||||
print_result("flush dcache():\t", total_size, flush_cost_time);
|
||||
|
||||
for (pt = 32; pt <= opt_size; pt <<= 1)
|
||||
{
|
||||
total_size = pt * repeat_cnt;
|
||||
invalidate_cost_time = 0;
|
||||
clean_cost_time = 0;
|
||||
flush_cost_time = 0;
|
||||
|
||||
if (pt < 1024)
|
||||
{
|
||||
printf("______do %" PRIu32 " B operation______\n", pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("______do %" PRIu32 " KB operation______\n", pt / 1024);
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
for (cnt = 0; cnt < repeat_cnt; cnt++)
|
||||
{
|
||||
uint32_t start_time;
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_invalidate_dcache((uintptr_t)begin,
|
||||
(uintptr_t)((uint8_t *)begin + pt));
|
||||
invalidate_cost_time += get_time_elaps(start_time);
|
||||
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_clean_dcache((uintptr_t)begin,
|
||||
(uintptr_t)((uint8_t *)begin + pt));
|
||||
clean_cost_time += get_time_elaps(start_time);
|
||||
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_flush_dcache((uintptr_t)begin,
|
||||
(uintptr_t)((uint8_t *)begin + pt));
|
||||
flush_cost_time += get_time_elaps(start_time);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
print_result("invalidate dcache():\t",
|
||||
total_size, invalidate_cost_time);
|
||||
print_result("clean dcache():\t", total_size, clean_cost_time);
|
||||
print_result("flush dcache():\t", total_size, flush_cost_time);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: icache_speed_test
|
||||
****************************************************************************/
|
||||
|
||||
static void icache_speed_test(FAR void *begin, size_t memset_size,
|
||||
size_t opt_size, uint32_t repeat_cnt)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int32_t cnt;
|
||||
uint32_t pt;
|
||||
uint32_t invalidate_cost_time = 0;
|
||||
|
||||
/* Accumulate the time to get the total time */
|
||||
|
||||
printf("______icache performance______\n");
|
||||
|
||||
printf("______do all operation______\n");
|
||||
flags = enter_critical_section();
|
||||
for (cnt = 0; cnt < repeat_cnt; cnt++)
|
||||
{
|
||||
uint32_t start_time;
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_invalidate_icache_all();
|
||||
invalidate_cost_time += get_time_elaps(start_time);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
print_result("invalidate dcache():\t",
|
||||
memset_size * repeat_cnt, invalidate_cost_time);
|
||||
|
||||
for (pt = 32; pt <= memset_size; pt <<= 1)
|
||||
{
|
||||
const size_t total_size = pt * repeat_cnt;
|
||||
invalidate_cost_time = 0;
|
||||
if (pt < 1024)
|
||||
{
|
||||
printf("______do %" PRIu32 " B operation______\n", pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("______do %" PRIu32 " KB operation______\n", pt / 1024);
|
||||
}
|
||||
|
||||
flags = enter_critical_section();
|
||||
for (cnt = 0; cnt < repeat_cnt; cnt++)
|
||||
{
|
||||
uint32_t start_time;
|
||||
memset(begin, 0, memset_size);
|
||||
start_time = get_perf_time();
|
||||
up_invalidate_icache((uintptr_t)begin,
|
||||
(uintptr_t)((uint8_t *)begin + pt));
|
||||
invalidate_cost_time += get_time_elaps(start_time);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
print_result("invalidate icache():\t",
|
||||
total_size, invalidate_cost_time);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: cachespeed_main
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
struct cachespeed_s cachespeed;
|
||||
|
||||
/* Setup defaults and parse the command line */
|
||||
|
||||
parse_commandline(argc, argv, &cachespeed);
|
||||
|
||||
/* Perform the dcache and icache test */
|
||||
|
||||
dcache_speed_test(cachespeed.begin, cachespeed.memset_size,
|
||||
cachespeed.opt_size, cachespeed.repeat_num);
|
||||
|
||||
icache_speed_test(cachespeed.begin, cachespeed.memset_size,
|
||||
cachespeed.opt_size, cachespeed.repeat_num);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user