examples/smart-test: Adds a circular log type test for SMARTFS wear level code testing. From Ken Petit
This commit is contained in:
parent
c0fa1d0970
commit
efbbd7bac0
@ -58,9 +58,14 @@
|
||||
|
||||
static int *g_linePos;
|
||||
static int *g_lineLen;
|
||||
static int g_seekCount = 0;
|
||||
static int g_writeCount = 0;
|
||||
static int g_circCount = 0;
|
||||
|
||||
static int g_lineCount = 2000;
|
||||
static int g_seekCount = 2000;
|
||||
static int g_writeCount = 2000;
|
||||
static int g_recordLen = 64;
|
||||
static int g_eraseCount = 32;
|
||||
static int g_totalRecords = 40000;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -344,6 +349,239 @@ static int smart_seek_with_write_test(char *filename)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_circular_log_test
|
||||
*
|
||||
* Description: Conducts a record based circular log seek / update test
|
||||
*
|
||||
* NOTE!!!
|
||||
* In the test below, we use open / write, not fopen / fwrite. If the
|
||||
* fopen / fwrite routines were used instead, they would provide us with
|
||||
* stream buffer management which we DO NOT WANT. This will throw off
|
||||
* the SMARTFS write sizes which will not generate the optimized wear
|
||||
* operations.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int smart_circular_log_test(char *filename)
|
||||
{
|
||||
int fd;
|
||||
char *buffer;
|
||||
char *cmpbuf;
|
||||
int s1;
|
||||
int x;
|
||||
int recordNo;
|
||||
int bufSize;
|
||||
int pass = TRUE;
|
||||
|
||||
/* Calculate the size of our granular "erase record" writes */
|
||||
|
||||
bufSize = g_recordLen * g_eraseCount;
|
||||
if (bufSize == 0)
|
||||
{
|
||||
printf("Invalid record parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Allocate memory for the record */
|
||||
|
||||
buffer = malloc(bufSize);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
printf("Unable to allocate memory for record storage\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate memory for the compare buffer */
|
||||
|
||||
cmpbuf = malloc(g_recordLen);
|
||||
if (cmpbuf == NULL)
|
||||
{
|
||||
printf("Unable to allocate memory for record storage\n");
|
||||
free(buffer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Open the circular log file */
|
||||
|
||||
fd = open(filename, O_RDWR | O_CREAT);
|
||||
if (fd == -1)
|
||||
{
|
||||
printf("Unable to create file %s\n", filename);
|
||||
free(buffer);
|
||||
free(cmpbuf);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Now fill the circular log with dummy 0xFF data */
|
||||
|
||||
printf("Creating circular log with %d records\n", g_totalRecords);
|
||||
memset(buffer, 0xFF, g_recordLen);
|
||||
for (x = 0; x < g_totalRecords; x++)
|
||||
{
|
||||
write(fd, buffer, g_recordLen);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Now reopen the file for read/write mode */
|
||||
|
||||
fd = open(filename, O_RDWR);
|
||||
if (fd == -1)
|
||||
{
|
||||
printf("Unable to open file %s\n", filename);
|
||||
free(buffer);
|
||||
free(cmpbuf);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
printf("Performing %d circular log record update tests\n",
|
||||
g_circCount);
|
||||
|
||||
/* Start at record number zero and start updating log entries */
|
||||
|
||||
recordNo = 0;
|
||||
for (x = 0; x < g_circCount; x++)
|
||||
{
|
||||
/* Fill a new record with random data */
|
||||
|
||||
for (s1=0; s1 < g_recordLen; s1++)
|
||||
{
|
||||
buffer[s1] = rand() & 0xFF;
|
||||
}
|
||||
|
||||
/* Set the first byte of the record (flag byte) to 0xFF */
|
||||
|
||||
buffer[0] = 0xFF;
|
||||
|
||||
/* Seek to the record location in the file */
|
||||
|
||||
lseek(fd, g_recordLen*recordNo, SEEK_SET);
|
||||
|
||||
/* Write the new record to the file */
|
||||
|
||||
if ((recordNo & (g_eraseCount-1)) == 0)
|
||||
{
|
||||
/* Every g_eraseCount records we will write a larger
|
||||
* buffer with our record and padded with 0xFF to
|
||||
* the end of our larger buffer.
|
||||
*/
|
||||
|
||||
memset(&buffer[g_recordLen], 0xFF, bufSize-g_recordLen);
|
||||
write(fd, buffer, bufSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just write a single record */
|
||||
|
||||
write(fd, buffer, g_recordLen);
|
||||
}
|
||||
|
||||
/* Now perform a couple of simulated flag updates */
|
||||
|
||||
lseek(fd, g_recordLen*recordNo, SEEK_SET);
|
||||
buffer[0] = 0xFE;
|
||||
write(fd, buffer, 1);
|
||||
lseek(fd, g_recordLen*recordNo, SEEK_SET);
|
||||
buffer[0] = 0xFC;
|
||||
write(fd, buffer, 1);
|
||||
|
||||
/* Now read the data back and compare it */
|
||||
|
||||
lseek(fd, g_recordLen*recordNo, SEEK_SET);
|
||||
read(fd, cmpbuf, g_recordLen);
|
||||
|
||||
for (s1 = 0; s1 < g_recordLen; s1++)
|
||||
{
|
||||
if (buffer[s1] != cmpbuf[s1])
|
||||
{
|
||||
printf("\nCompare failure in record %d, offset %d\n",
|
||||
recordNo, recordNo*g_recordLen+s1);
|
||||
printf("\tExpected \"%02x\"", cmpbuf[s1]);
|
||||
printf("\rReceived \"%02x\"", buffer[s1]);
|
||||
pass = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\r%d", x);
|
||||
fflush(stdout);
|
||||
|
||||
/* Increment to the next record */
|
||||
|
||||
if (++recordNo >= g_totalRecords)
|
||||
{
|
||||
recordNo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pass)
|
||||
{
|
||||
printf("\nPass\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\nFail\n");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
free(buffer);
|
||||
free(cmpbuf);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: smart_usage
|
||||
*
|
||||
* Description: Displays usage information for the command.
|
||||
*
|
||||
****************************************************************************/
|
||||
static void smart_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: smart_test [-c COUNT] [-s SEEKCOUNT] [-w WRITECOUNT] smart_mounted_filename\n\n");
|
||||
|
||||
fprintf(stderr, "DESCRIPTION\n");
|
||||
fprintf(stderr, " Conducts various stress tests to validate SMARTFS operation.\n");
|
||||
fprintf(stderr, " Please choose one or more of -c, -s, or -w to conduct tests.\n\n");
|
||||
|
||||
fprintf(stderr, "OPTIONS\n");
|
||||
fprintf(stderr, " -c COUNT\n");
|
||||
fprintf(stderr, " Performs a circular log style test where a fixed number of fixed\n");
|
||||
fprintf(stderr, " length records are written and then overwritten with new data.\n");
|
||||
fprintf(stderr, " Uses the -r, -e and -t options to specify the parameters of the \n");
|
||||
fprintf(stderr, " record geometry and update operation. The COUNT parameter sets\n");
|
||||
fprintf(stderr, " the number of record updates to perform.\n\n");
|
||||
|
||||
fprintf(stderr, " -s SEEKCOUNT\n");
|
||||
fprintf(stderr, " Performs a simple seek test where to validate the SMARTFS seek\n");
|
||||
fprintf(stderr, " operation. Uses the -l option to specify the number of test\n");
|
||||
fprintf(stderr, " lines to write to the test file. The SEEKCOUNT parameter sets\n");
|
||||
fprintf(stderr, " the number of seek/read operations to perform.\n\n");
|
||||
|
||||
fprintf(stderr, " -w WRITECOUNT\n");
|
||||
fprintf(stderr, " Performs a seek/write/seek/read test where to validate the SMARTFS\n");
|
||||
fprintf(stderr, " seek/write operation. Uses the -l option to specifiy the number of\n");
|
||||
fprintf(stderr, " test lines to write to the test file. The WRITECOUNT parameter sets\n");
|
||||
fprintf(stderr, " the number of seek/write operations to perform.\n\n");
|
||||
|
||||
fprintf(stderr, " -l LINECOUNT\n");
|
||||
fprintf(stderr, " Sets the number of lines of test data to write to the test file\n");
|
||||
fprintf(stderr, " during seek and seek/write tests.\n\n");
|
||||
|
||||
fprintf(stderr, " -r RECORDLEN\n");
|
||||
fprintf(stderr, " Sets the length of each log record during circular log tests.\n\n");
|
||||
|
||||
fprintf(stderr, " -e ERASECOUNT\n");
|
||||
fprintf(stderr, " Sets the erase granularity for overwriting old circular log entries.\n");
|
||||
fprintf(stderr, " Setting this value to 16, for instance, would cause every 16th record\n");
|
||||
fprintf(stderr, " update to write a single record followed by 15 records with all 0xFF\n");
|
||||
fprintf(stderr, " content. This helps SMARTFS perform better wear leveling and reduces\n");
|
||||
fprintf(stderr, " the number of FLASH block erases significantly.\n\n");
|
||||
|
||||
fprintf(stderr, " -t TOTALRECORDS\n");
|
||||
fprintf(stderr, " Sets the total number of records in the circular log test file.\n\n");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -355,35 +593,50 @@ int smart_test_main(int argc, char *argv[])
|
||||
#endif
|
||||
{
|
||||
int ret, opt;
|
||||
int gTestCount = 10000;
|
||||
|
||||
/* Argument given? */
|
||||
|
||||
while ((opt = getopt(argc, argv, "l:s:w:")) != -1)
|
||||
while ((opt = getopt(argc, argv, "c:e:l:r:s:t:w:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'c':
|
||||
g_circCount = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
g_eraseCount = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
g_lineCount = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
g_recordLen = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
g_seekCount = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
g_totalRecords = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
g_writeCount = atoi(optarg);
|
||||
break;
|
||||
|
||||
default: /* '?' */
|
||||
fprintf(stderr, "usage: smart_test [-l lineCount] [-s seekCount] [-w writeCount] smart_mounted_filename\n");
|
||||
smart_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2)
|
||||
if (argc < 2 || (g_seekCount + g_writeCount + g_circCount == 0))
|
||||
{
|
||||
fprintf(stderr, "usage: smart_test [-l lineCount] [-s seekCount] [-w writeCount] smart_mounted_filename\n");
|
||||
smart_usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -402,30 +655,48 @@ int smart_test_main(int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a test file */
|
||||
/* Test if performing seek test or write test */
|
||||
|
||||
if ((ret = smart_create_test_file(argv[optind])) < 0)
|
||||
if (g_seekCount > 0 || g_writeCount > 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
/* Create a test file */
|
||||
|
||||
if ((ret = smart_create_test_file(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
|
||||
/* Conduct a seek test? */
|
||||
|
||||
if (g_seekCount > 0 )
|
||||
{
|
||||
if ((ret = smart_seek_test(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Conduct an append test */
|
||||
|
||||
if ((ret = smart_append_test(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
|
||||
/* Conduct a seek with write test? */
|
||||
|
||||
if (g_writeCount > 0)
|
||||
{
|
||||
if ((ret = smart_seek_with_write_test(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Conduct a seek test */
|
||||
/* Perform a "circular log" test */
|
||||
|
||||
if ((ret = smart_seek_test(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
|
||||
/* Conduct an append test */
|
||||
|
||||
if ((ret = smart_append_test(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
|
||||
/* Conduct a seek with write test */
|
||||
|
||||
if ((ret = smart_seek_with_write_test(argv[optind])) < 0)
|
||||
if ((ret = smart_circular_log_test(argv[optind])) < 0)
|
||||
{
|
||||
goto err_out_with_mem;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user