benchmark/mtd: Add MTD testing/benchmark application

This test allows measuring write and read operations on an MTD
flash device, evaluating its transfer rates.

Signed-off-by: Tiago Medicci <tiago.medicci@espressif.com>
This commit is contained in:
Tiago Medicci 2025-03-19 14:23:27 -03:00 committed by Xiang Xiao
parent cdc5968c67
commit 494554618e
5 changed files with 317 additions and 0 deletions

View file

@ -0,0 +1,33 @@
# ##############################################################################
# apps/benchmarks/mtd/CMakeLists.txt
#
# SPDX-License-Identifier: Apache-2.0
#
# 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.
#
# ##############################################################################
if(CONFIG_BENCHMARK_MTD)
nuttx_add_application(
NAME
mtd
STACKSIZE
${CONFIG_DEFAULT_TASK_STACKSIZE}
MODULE
${CONFIG_BENCHMARK_MTD}
SRCS
mtd.c)
endif()

18
benchmarks/mtd/Kconfig Normal file
View file

@ -0,0 +1,18 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config BENCHMARK_MTD
tristate "MTD test and transfer rate benchmark"
default n
depends on BUILD_FLAT && MTD
---help---
This testing/benchmark application performs an erase/write
operation to evaluate write transfer rate and then reads the
written content back to evaluate the read transfer rate. Finally,
it compares the read data with the previously written data to
ensure the MTD device is working as expected.
NOTE: This application uses internal OS interfaces and so it is not
available in the NuttX kernel build.

25
benchmarks/mtd/Make.defs Normal file
View file

@ -0,0 +1,25 @@
############################################################################
# apps/benchmarks/mtd/Make.defs
#
# SPDX-License-Identifier: Apache-2.0
#
# 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_BENCHMARK_MTD),)
CONFIGURED_APPS += $(APPDIR)/benchmarks/mtd/
endif

34
benchmarks/mtd/Makefile Normal file
View file

@ -0,0 +1,34 @@
############################################################################
# apps/benchmarks/mtd/Makefile
#
# SPDX-License-Identifier: Apache-2.0
#
# 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
# MTD test and transfer rate benchmark
PROGNAME = mtd
PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
MODULE = $(CONFIG_BENCHMARK_MTD)
MAINSRC = mtd.c
include $(APPDIR)/Application.mk

207
benchmarks/mtd/mtd.c Normal file
View file

@ -0,0 +1,207 @@
/****************************************************************************
* apps/benchmarks/mtd/mtd.c
*
* SPDX-License-Identifier: Apache-2.0
*
* 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 <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/fs/smart.h>
#include <nuttx/fs/ioctl.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private data
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, FAR char *argv[])
{
struct inode *inode;
struct timespec start;
struct timespec end;
struct mtd_geometry_s geo;
struct partition_info_s info;
int ret;
int x;
double elapsed_time;
double transfer_rate;
size_t total_bytes_written = 0;
size_t total_bytes_read = 0;
char *buffer;
/* Argument given? */
if (argc < 2)
{
fprintf(stderr, "usage: mtd flash_block_device\n");
return -1;
}
/* Find the inode of the block driver identified by 'source' */
ret = open_blockdriver(argv[1], 0, &inode);
if (ret < 0)
{
fprintf(stderr, "Failed to open %s\n", argv[1]);
return ret;
}
/* Get the low-level format from the device. */
ret = inode->u.i_bops->ioctl(inode, BIOC_PARTINFO, (unsigned long) &info);
if (ret != OK)
{
fprintf(stderr, "Device is not a block device\n");
goto errout_with_driver;
}
/* Get the MTD geometry */
ret = inode->u.i_bops->ioctl(inode, MTDIOC_GEOMETRY, (unsigned long) &geo);
if (ret != OK)
{
fprintf(stderr, "Device is not a MTD device\n");
goto errout_with_driver;
}
/* Report the device structure */
printf("FLASH device parameters:\n");
printf(" Sector size: %10d\n", info.sectorsize);
printf(" Sector count: %10d\n", info.numsectors);
printf(" Erase block: %10d\n", geo.erasesize);
printf(" Total size: %10d\n", info.sectorsize * info.numsectors);
if (info.sectorsize != geo.erasesize)
{
fprintf(stderr, "Sector size does not match the erase block size.\n"
"Please adjust the sector size to enable erasing and writing "
"without using an intermediary read buffer.\n");
goto errout_with_driver;
}
/* Allocate buffers to use */
buffer = (char *)malloc(info.sectorsize);
if (buffer == NULL)
{
fprintf(stderr, "Error allocating buffer\n");
goto errout_with_driver;
}
/* Fill the buffer with known data and print it in hex format */
for (int i = 0; i < info.sectorsize; i++)
{
buffer[i] = (char)(i & 0xff);
}
/* Now write some data to the sector */
printf("\nStarting write operation...\n");
clock_gettime(CLOCK_MONOTONIC, &start);
for (x = 0; x < info.numsectors; x++)
{
inode->u.i_bops->write(inode, (const unsigned char *)buffer, x, 1);
total_bytes_written += info.sectorsize;
}
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed_time = (end.tv_sec - start.tv_sec) + \
(end.tv_nsec - start.tv_nsec) / 1e9;
transfer_rate = (total_bytes_written / elapsed_time) / 1024;
printf("\nWrite operation completed in %.2f seconds\n", elapsed_time);
printf("Total bytes written: %zu\n", total_bytes_written);
printf("Transfer rate [write]: %.2f KiB/s\n", transfer_rate);
/* Now read the data back to validate everything was written and can
* be read.
*/
printf("\nStarting read operation...\n");
clock_gettime(CLOCK_MONOTONIC, &start);
for (x = 0; x < info.numsectors; x++)
{
inode->u.i_bops->read(inode, (unsigned char *)buffer, x, 1);
total_bytes_read += info.sectorsize;
}
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed_time = (end.tv_sec - start.tv_sec) + \
(end.tv_nsec - start.tv_nsec) / 1e9;
transfer_rate = (total_bytes_written / elapsed_time) / 1024;
printf("\nRead operation completed in %.2f seconds\n", elapsed_time);
printf("Total bytes read: %zu\n", total_bytes_read);
printf("Transfer rate [read]: %.2f KiB/s\n", transfer_rate);
/* Compare the read data with the written data */
for (int i = 0; i < info.sectorsize; i++)
{
if (buffer[i] != (char)(i & 0xff))
{
printf("\nData mismatch at byte %d: expected %02X, got %02X\n",
i, (unsigned char)(i & 0xff), (unsigned char)buffer[i]);
goto errout_with_buffers;
}
}
printf("\nData verification successful: read data matches written data\n");
errout_with_buffers:
/* Free the allocated buffers */
free(buffer);
errout_with_driver:
/* Now close the block device and exit */
close_blockdriver(inode);
return 0;
}