nuttx-apps/benchmarks/cachespeed/cachespeed_main.c
chenrun1 12012f2276 cachespeed:Fixed the problem of printing variables in 32/64-bit environment
Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
2024-08-18 03:14:24 +08:00

253 lines
7.5 KiB
C

/****************************************************************************
* apps/benchmarks/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/config.h>
#include <nuttx/irq.h>
#include <inttypes.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define CACHESPEED_PREFIX "CACHE Speed: "
#define REPEAT_NUM 1000
#ifdef CACHESPEED_PERFTIME
#define TIME uint64_t
#define CONVERT(cost) \
do \
{ \
struct timespec ts; \
perf_convert(cost, &ts); \
cost = ts.tv_sec * 1000000000 + ts.tv_nsec; \
} while (0)
#define TIMESTAMP(x) (x) = perf_gettime()
#else
#define TIME time_t
#define CONVERT(cost)
#define TIMESTAMP(x) \
do \
{ \
struct timespec ts; \
clock_gettime(CLOCK_MONOTONIC, &ts); \
x = ts.tv_sec * 1000000000 + ts.tv_nsec; \
} while (0)
#endif
#define GET_DCACHE_LINE up_get_dcache_linesize()
#define GET_ICACHE_LINE up_get_icache_linesize()
#define GET_DCACHE_SIZE up_get_dcache_size()
#define GET_ICACHE_SIZE up_get_icache_size()
/****************************************************************************
* Private Types
****************************************************************************/
struct cachespeed_s
{
uintptr_t addr;
size_t alloc;
};
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: setup
****************************************************************************/
static void setup(FAR struct cachespeed_s *cs)
{
struct mallinfo info = mallinfo();
/* Get the currently available memory from the system. We want the
* memset range to be as large as possible in our tests to ensure
* that the cache is filled with our dirty data
*/
cs->alloc = info.fordblks / 2;
cs->addr = (uintptr_t)malloc(cs->alloc);
if (cs->addr == 0)
{
printf(CACHESPEED_PREFIX "Unable to request memory.\n");
exit(EXIT_FAILURE);
}
/* Let's export the test message */
printf(CACHESPEED_PREFIX "address src: %" PRIxPTR "\n", cs->addr);
}
/****************************************************************************
* Name: teardown
****************************************************************************/
static void teardown(FAR struct cachespeed_s *cs)
{
free((void *)cs->addr);
printf(CACHESPEED_PREFIX "Done!\n");
}
/****************************************************************************
* Name: report_line
****************************************************************************/
static void report_line(size_t bytes, TIME cost)
{
double rate;
/* There is a situation: if the time is 0, then the
* calculated speed is wrong.
*/
CONVERT(cost);
if (cost == 0)
{
printf(CACHESPEED_PREFIX "%zu bytes cost time too small!\n", bytes);
return;
}
/* rate = Test Data Size / Execution Time */
rate = 1.00 * bytes * REPEAT_NUM / cost;
printf("%zu Bytes: %4lf, %4" PRIu64", %4" PRIu64"\n\r",
bytes, rate, cost / REPEAT_NUM, cost);
}
/****************************************************************************
* Name: test_skeleton
****************************************************************************/
static void test_skeleton(FAR struct cachespeed_s *cs,
const size_t cache_size,
const size_t cache_line_size, int align,
void (*func)(uintptr_t, uintptr_t),
const char *name)
{
size_t update_size;
printf("** %s [rate, avg, cost] in nanoseconds(bytes/nesc) %s **\n",
name, align ? "align" : "unalign");
if (!align)
{
update_size = cache_line_size - 1;
}
else
{
update_size = cache_line_size;
}
for (size_t bytes = update_size;
bytes <= cache_size; bytes = 2 * bytes)
{
irqstate_t irq;
TIME start;
TIME end;
TIME cost = 0;
/* Make sure that test with all the contents
* of our address in the cache.
*/
up_flush_dcache_all();
irq = enter_critical_section();
for (int i = 0; i < REPEAT_NUM; i++)
{
memset((void *)cs->addr, 1, cs->alloc);
TIMESTAMP(start);
func(cs->addr, (uintptr_t)(cs->addr + bytes));
TIMESTAMP(end);
cost += end - start;
}
leave_critical_section(irq);
report_line(bytes, cost);
}
}
/****************************************************************************
* Name: cachespeed_common
****************************************************************************/
static void cachespeed_common(struct cachespeed_s *cs)
{
test_skeleton(cs, GET_DCACHE_SIZE, GET_DCACHE_LINE, 1,
up_invalidate_dcache, "dcache invalidate");
test_skeleton(cs, GET_DCACHE_SIZE, GET_DCACHE_LINE, 0,
up_invalidate_dcache, "dcache invalidate");
test_skeleton(cs, GET_DCACHE_SIZE, GET_DCACHE_LINE, 1,
up_clean_dcache, "dcache clean");
test_skeleton(cs, GET_DCACHE_SIZE, GET_DCACHE_LINE, 0,
up_clean_dcache, "dcache clean");
test_skeleton(cs, GET_DCACHE_SIZE, GET_DCACHE_LINE, 1,
up_flush_dcache, "dcache flush");
test_skeleton(cs, GET_DCACHE_SIZE, GET_DCACHE_LINE, 0,
up_flush_dcache, "dcache flush");
test_skeleton(cs, GET_ICACHE_SIZE, GET_ICACHE_LINE, 1,
up_invalidate_icache, "icache invalidate");
test_skeleton(cs, GET_ICACHE_SIZE, GET_ICACHE_LINE, 0,
up_invalidate_icache, "icache invalidate");
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: cachespeed_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
struct cachespeed_s cs =
{
.addr = 0,
.alloc = 0
};
setup(&cs);
cachespeed_common(&cs);
teardown(&cs);
return 0;
}