davids5 commented on code in PR #2164: URL: https://github.com/apache/nuttx-apps/pull/2164#discussion_r1372553920
########## testing/sd_bench/sd_bench_main.c: ########## @@ -0,0 +1,476 @@ +/**************************************************************************** + * apps/testing/sd_bench/sd_bench_main.c + * + * Original Licence: + * + * Copyright (c) 2016-2021 PX4 Development Team. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name PX4 nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/* Originally ported from PX4 https://github.com/PX4/PX4-Autopilot, + * with the following additions: + * + * - All allocated memory buffers are unaligned. + * - Refactoring for NuttX code style. + * - Test result output has been modified to display total MB written. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <nuttx/clock.h> + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef struct sdb_config +{ + int num_runs; + int run_duration; + bool synchronized; + size_t total_blocks_written; +} sdb_config_t; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const char *BENCHMARK_FILE = + CONFIG_TESTING_SD_BENCH_DEVICE "/sd_bench"; + +const size_t max_block = 65536; +const size_t min_block = 1; +const size_t default_block = 512; + +const size_t max_runs = 10000; +const size_t min_runs = 1; +const size_t default_runs = 5; + +const size_t max_duration = 60000; +const size_t min_duration = 1; +const size_t default_duration = 2000; + +const bool default_keep_test = false; +const bool default_fsync = false; +const bool default_verify = true; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void write_test(int fd, sdb_config_t *cfg, uint8_t *block, + int block_size); +static int read_test(int fd, sdb_config_t *cfg, uint8_t *block, + int block_size); + +static uint64_t time_fsync_us(int fd); +struct timespec get_abs_time(void); +uint64_t get_elapsed_time_us(const struct timespec *start); +uint64_t time_fsync_us(int fd); +float ts_to_kb(uint64_t bytes, uint64_t elapsed); +float block_count_to_mb(size_t blocks, size_t block_size); +static const char *print_bool(const bool value); +static void usage(void); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +struct timespec get_abs_time(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts; +} + +uint64_t get_time_delta_us(const struct timespec *start, + const struct timespec *end) +{ + uint64_t elapsed; + elapsed = (((uint64_t)end->tv_sec * NSEC_PER_SEC) + end->tv_nsec); + elapsed -= (((uint64_t)start->tv_sec * NSEC_PER_SEC) + start->tv_nsec); + return elapsed / 1000.; +} + +uint64_t get_elapsed_time_us(const struct timespec *start) +{ + struct timespec now = get_abs_time(); + return get_time_delta_us(start, &now); +} + +uint64_t time_fsync_us(int fd) +{ + struct timespec start = get_abs_time(); + fsync(fd); + return get_elapsed_time_us(&start); +} + +float ts_to_kb(uint64_t bytes, uint64_t elapsed) +{ + return (bytes / 1024.) / (elapsed / 1e6); +} + +float block_count_to_mb(size_t blocks, size_t block_size) +{ + return blocks * block_size / (float)(1024 * 1024); +} + +static const char *print_bool(const bool value) +{ + return value ? "true" : "false"; +} + +void write_test(int fd, sdb_config_t *cfg, uint8_t *block, int block_size) +{ + struct timespec start; + struct timespec write_start; + size_t written; + size_t num_blocks; + uint64_t max_write_time; + uint64_t fsync_time; + uint64_t write_time; + uint64_t elapsed; + uint64_t total_elapsed = 0.; + size_t total_blocks = 0; + size_t *blocknumber = (unsigned int *)(void *)&block[0]; + + printf("\n"); + printf("Testing Sequential Write Speed...\n"); + + cfg->total_blocks_written = 0; + + for (int run = 0; run < cfg->num_runs; ++run) + { + start = get_abs_time(); + num_blocks = 0; + max_write_time = 0; + fsync_time = 0; + + while (get_elapsed_time_us(&start) < cfg->run_duration) + { + *blocknumber = total_blocks + num_blocks; + write_start = get_abs_time(); + written = write(fd, block, block_size); + write_time = get_elapsed_time_us(&write_start); + + if (write_time > max_write_time) + { + max_write_time = write_time; + } + + if ((int)written != block_size) + { + printf("Write error: %d\n", errno); + return; + } + + if (cfg->synchronized) + { + fsync_time += time_fsync_us(fd); + } + + ++num_blocks; + } + + /* Note: if testing a slow device (SD Card) and the OS buffers a lot, + * fsync can take really long, and it looks like the process hangs. + * But it does not and the reported result will still be correct. + */ + + if (!cfg->synchronized) + { + fsync_time += time_fsync_us(fd); + } + + elapsed = get_elapsed_time_us(&start); + printf(" Run %2i: %8.1f KB/s, max write time: %4.3f ms (%.1f KB/s), " + "fsync: %4.3f ms\n", run + 1, + ts_to_kb(block_size * num_blocks, elapsed), + max_write_time / 1.e3, + ts_to_kb(block_size, max_write_time), fsync_time / 1e3); + + total_elapsed += elapsed; + total_blocks += num_blocks; + } + + cfg->total_blocks_written = total_blocks; + printf(" Avg : %8.1f KB/s, %3.3f MB written.\n", + ts_to_kb(block_size * total_blocks, total_elapsed), + block_count_to_mb(total_blocks, block_size)); +} + +int read_test(int fd, sdb_config_t *cfg, uint8_t *block, int block_size) +{ + uint8_t *read_block; + uint64_t total_elapsed; + size_t total_blocks; + struct timespec start; + size_t num_blocks; + uint64_t max_read_time; + uint64_t read_time; + uint64_t elapsed; + struct timespec read_start; + size_t nread; + + printf("\n"); + printf("Testing Sequential Read Speed...\n"); + + read_block = (uint8_t *)malloc(block_size); + + if (!read_block) + { + printf("Failed to allocate memory block\n"); + return -1; + } + + total_elapsed = 0.; + total_blocks = 0; + size_t *blocknumber = (unsigned int *)(void *) &read_block[0]; + + for (int run = 0; run < cfg->num_runs; ++run) + { + start = get_abs_time(); + num_blocks = 0; + max_read_time = 0; + + while (get_elapsed_time_us(&start) < cfg->run_duration + && total_blocks + num_blocks < cfg->total_blocks_written) + { + read_start = get_abs_time(); + nread = read(fd, read_block, block_size); + read_time = get_elapsed_time_us(&read_start); + + if (read_time > max_read_time) + { + max_read_time = read_time; + } + + if ((int)nread != block_size) + { + printf("Read error\n"); + free(read_block); + return -1; + } + + if (*blocknumber != total_blocks + num_blocks) + { + printf("Read data error at block: %d wrote:0x%04x read:0x%04x", + (total_blocks + num_blocks), + total_blocks + num_blocks, *blocknumber); + } + + for (unsigned int i = sizeof(*blocknumber); + i < (block_size - sizeof(*blocknumber)); ++i) + { + if (block[i] != read_block[i]) + { + printf("Read data error at offset: %d wrote:0x%02x " + "read:0x%02x", total_blocks + num_blocks + i, + block[i], read_block[i]); + } + } + + ++num_blocks; + } + + elapsed = get_elapsed_time_us(&start); + + if (num_blocks) + { + printf(" Run %2i: %8.1f KB/s, max read/verify time: %3.4f ms " + "(%.1f KB/s)\n", run + 1, + ts_to_kb(block_size * num_blocks, elapsed), + max_read_time / 1e3, + ts_to_kb(block_size, max_read_time)); + + total_elapsed += elapsed; + total_blocks += num_blocks; + } + } + + printf(" Avg : %8.1f KB/s, %3.3f MB and verified\n", + ts_to_kb(block_size * total_blocks, total_elapsed), + block_count_to_mb(total_blocks, block_size)); + + free(read_block); + return 0; +} + +static void usage(void) +{ + printf("Test the speed of an SD card or mount point\n"); + printf(CONFIG_TESTING_SD_BENCH_PROGNAME + ": [-b] [-r] [-d] [-k] [-s] [-u] [-v]\n"); Review Comment: You removed unaligned. but -u is still here. Personally I think unaligned is critical to the test. It demonstrates the performance hit with the FAT DMA allocator and the whole preflight fail - rerun cycle. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org