memorystress:For pressure detection of memory stability
Signed-off-by: chenrun1 <chenrun1@xiaomi.com>
This commit is contained in:
parent
1309990d6c
commit
4a78dedbae
29
system/memstress/Kconfig
Normal file
29
system/memstress/Kconfig
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config SYSTEM_MEMORY_STRESS
|
||||
tristate "memory stress test"
|
||||
default n
|
||||
---help---
|
||||
Enable a memory stress test.
|
||||
|
||||
if SYSTEM_MEMORY_STRESS
|
||||
|
||||
config SYSTEM_MEMORY_STRESS_PROGNAME
|
||||
string "Program name"
|
||||
default "memstress"
|
||||
---help---
|
||||
This is the name of the program that will be used when the NSH ELF
|
||||
program is installed.
|
||||
|
||||
config SYSTEM_MEMORY_STRESS_PRIORITY
|
||||
int "MEMORY stress task priority"
|
||||
default 100
|
||||
|
||||
config SYSTEM_MEMORY_STRESS_STACKSIZE
|
||||
int "MEMORY stress stack size"
|
||||
default DEFAULT_TASK_STACKSIZE
|
||||
|
||||
endif
|
23
system/memstress/Make.defs
Normal file
23
system/memstress/Make.defs
Normal file
@ -0,0 +1,23 @@
|
||||
############################################################################
|
||||
# apps/system/memstress/Make.defs
|
||||
#
|
||||
# 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_MEMORY_STRESS),)
|
||||
CONFIGURED_APPS += $(APPDIR)/system/memstress
|
||||
endif
|
32
system/memstress/Makefile
Normal file
32
system/memstress/Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
############################################################################
|
||||
# apps/system/memstress/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
|
||||
|
||||
# RAM speed test
|
||||
|
||||
PROGNAME = $(CONFIG_SYSTEM_MEMORY_STRESS_PROGNAME)
|
||||
PRIORITY = $(CONFIG_SYSTEM_MEMORY_STRESS_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_SYSTEM_MEMORY_STRESS_STACKSIZE)
|
||||
MODULE = $(CONFIG_SYSTEM_MEMORY_STRESS)
|
||||
|
||||
MAINSRC = memorystress_main.c
|
||||
|
||||
include $(APPDIR)/Application.mk
|
509
system/memstress/memorystress_main.c
Normal file
509
system/memstress/memorystress_main.c
Normal file
@ -0,0 +1,509 @@
|
||||
/****************************************************************************
|
||||
* apps/system/memstress/memorystress_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/config.h>
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define MEMSTRESS_PREFIX "MemoryStress:"
|
||||
#define DEBUG_MAGIC 0xaa
|
||||
#define SEEK_MAGIC 0xabcdef
|
||||
|
||||
#define OPTARG_TO_VALUE(value, type) \
|
||||
do \
|
||||
{ \
|
||||
FAR char *ptr; \
|
||||
value = (type)strtoul(optarg, &ptr, 10); \
|
||||
if (*ptr != '\0') \
|
||||
{ \
|
||||
printf(MEMSTRESS_PREFIX "Parameter error -%c %s\n", ch, optarg); \
|
||||
show_usage(argv[0]); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type
|
||||
****************************************************************************/
|
||||
|
||||
enum memorystress_rwerror_e
|
||||
{
|
||||
MEMORY_STRESS_READ_ERROR,
|
||||
MEMORY_STRESS_WRITE_ERROR
|
||||
};
|
||||
|
||||
struct memorystress_func_s
|
||||
{
|
||||
void *(*malloc)(size_t size);
|
||||
void *(*aligned_alloc)(size_t align, size_t nbytes);
|
||||
void *(*realloc)(FAR void *ptr, size_t new_size);
|
||||
void (*freefunc)(FAR void *ptr);
|
||||
};
|
||||
|
||||
struct memorystress_config_s
|
||||
{
|
||||
FAR struct memorystress_func_s *func;
|
||||
size_t max_allocsize;
|
||||
size_t nodelen;
|
||||
};
|
||||
|
||||
struct memorystress_error_s
|
||||
{
|
||||
FAR uint8_t *buf;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
size_t cnt;
|
||||
uint8_t readvalue;
|
||||
uint8_t writevalue;
|
||||
enum memorystress_rwerror_e rwerror;
|
||||
};
|
||||
|
||||
struct memorystress_node_s
|
||||
{
|
||||
FAR uint8_t *buf;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct memorystress_context_s
|
||||
{
|
||||
struct memorystress_node_s *node_array;
|
||||
struct memorystress_config_s *config;
|
||||
struct memorystress_error_s error;
|
||||
uint32_t sleep_us;
|
||||
bool debug;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: show_usage
|
||||
****************************************************************************/
|
||||
|
||||
static void show_usage(FAR const char *progname)
|
||||
{
|
||||
printf("\nUsage: %s -m <max allocsize> -n <node length> -t <sleep us>"
|
||||
" -d [debuger mode]\n",
|
||||
progname);
|
||||
printf("\nWhere:\n");
|
||||
printf(" -m <max-allocsize> max alloc size.\n");
|
||||
printf(" -n <node length> Number of allocated memory blocks .\n");
|
||||
printf(" -t <sleep us> Length of time between each test.\n");
|
||||
printf(" -d [debug mode] Helps to localize the problem situation,"
|
||||
"there is a lot of information output in this mode.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: randnum
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t randnum(uint32_t max, FAR uint32_t *seed)
|
||||
{
|
||||
uint32_t x = *seed;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
*seed = x;
|
||||
return x % max;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: genvalue
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t genvalue(FAR uint32_t *seed, bool debug)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
return DEBUG_MAGIC;
|
||||
}
|
||||
|
||||
return randnum(UINT32_MAX, seed);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: checknode
|
||||
****************************************************************************/
|
||||
|
||||
static bool checknode(FAR struct memorystress_context_s *context,
|
||||
FAR struct memorystress_node_s *node)
|
||||
{
|
||||
size_t size = node->size;
|
||||
uint32_t seed = size;
|
||||
size_t i;
|
||||
|
||||
/* check data */
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
uint8_t write_value = genvalue(&seed, context->debug);
|
||||
uint8_t read_value = node->buf[i];
|
||||
|
||||
if (read_value != write_value)
|
||||
{
|
||||
context->error.buf = node->buf;
|
||||
context->error.size = node->size;
|
||||
context->error.offset = i;
|
||||
context->error.readvalue = read_value;
|
||||
context->error.writevalue = write_value;
|
||||
|
||||
if (context->debug)
|
||||
{
|
||||
lib_dumpbuffer("debuger", node->buf, size);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: error_result
|
||||
****************************************************************************/
|
||||
|
||||
static void error_result(struct memorystress_error_s error)
|
||||
{
|
||||
printf(MEMSTRESS_PREFIX "%s ERROR!, "
|
||||
"buf = %p, "
|
||||
"size = %zu, "
|
||||
"offset = %zu(addr = %p), "
|
||||
"cnt = %zu, "
|
||||
"readValue = 0x%x, "
|
||||
"writeValue = 0x%x\n",
|
||||
error.rwerror == MEMORY_STRESS_READ_ERROR ? "READ" : "WRITE",
|
||||
error.buf,
|
||||
error.size,
|
||||
error.offset, error.buf + error.offset,
|
||||
error.cnt,
|
||||
error.readvalue,
|
||||
error.writevalue);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: memorystress_iter
|
||||
****************************************************************************/
|
||||
|
||||
static bool memorystress_iter(FAR struct memorystress_context_s *context)
|
||||
{
|
||||
FAR struct memorystress_node_s *node;
|
||||
FAR struct memorystress_func_s *func;
|
||||
uint32_t seed = SEEK_MAGIC;
|
||||
bool debug = context->debug;
|
||||
size_t index;
|
||||
|
||||
index = randnum(context->config->nodelen, &seed);
|
||||
node = &(context->node_array[index]);
|
||||
func = (FAR struct memorystress_func_s *)context->config->func;
|
||||
|
||||
/* check state */
|
||||
|
||||
if (!node->buf)
|
||||
{
|
||||
/* Selection of test type and test size by random number */
|
||||
|
||||
FAR uint8_t *ptr;
|
||||
size_t size = randnum(context->config->max_allocsize, &seed);
|
||||
int switch_func = rand() % 3;
|
||||
int align = 1 << (rand() % 4 + 2);
|
||||
|
||||
/* There are currently three types of tests:
|
||||
* 0.standard malloc
|
||||
* 1.align_alloc
|
||||
* 2.realloc
|
||||
*/
|
||||
|
||||
switch (switch_func)
|
||||
{
|
||||
case 0:
|
||||
ptr = func->malloc(size);
|
||||
break;
|
||||
case 1:
|
||||
ptr = func->aligned_alloc(align, size);
|
||||
break;
|
||||
case 2:
|
||||
/* We have to allocate memory randomly once first,
|
||||
* otherwise realloc's behavior is equivalent to malloc
|
||||
*/
|
||||
|
||||
ptr = func->malloc(1024);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ptr = func->realloc(ptr, size);
|
||||
break;
|
||||
default:
|
||||
printf("Invalid switch_func number.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the pointer to the test, if it is null there
|
||||
* may not be enough memory allocated.
|
||||
*/
|
||||
|
||||
if (ptr == NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
node->buf = ptr;
|
||||
node->size = size;
|
||||
|
||||
/* fill random data */
|
||||
|
||||
seed = size;
|
||||
while (size--)
|
||||
{
|
||||
*ptr++ = genvalue(&seed, debug);
|
||||
}
|
||||
|
||||
/* Check write success */
|
||||
|
||||
if (!checknode(context, node))
|
||||
{
|
||||
/* free node */
|
||||
|
||||
context->error.rwerror = MEMORY_STRESS_WRITE_ERROR;
|
||||
func->freefunc(node->buf);
|
||||
node->buf = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check read */
|
||||
|
||||
if (!checknode(context, node))
|
||||
{
|
||||
context->error.rwerror = MEMORY_STRESS_READ_ERROR;
|
||||
}
|
||||
|
||||
/* free node */
|
||||
|
||||
func->freefunc(node->buf);
|
||||
node->buf = NULL;
|
||||
|
||||
if (context->error.buf)
|
||||
{
|
||||
/* stop test */
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
context->error.cnt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: debug_malloc
|
||||
****************************************************************************/
|
||||
|
||||
static FAR void *debug_malloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
syslog(LOG_INFO, MEMSTRESS_PREFIX "malloc: %zu bytes, ptr = %p\n",
|
||||
size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: debug_free
|
||||
****************************************************************************/
|
||||
|
||||
static void debug_free(FAR void *ptr)
|
||||
{
|
||||
syslog(LOG_INFO, MEMSTRESS_PREFIX "free: %p\n", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: debug_aligned_alloc
|
||||
****************************************************************************/
|
||||
|
||||
static FAR void *debug_aligned_alloc(size_t align, size_t nbytes)
|
||||
{
|
||||
void *ptr = memalign(align, nbytes);
|
||||
syslog(LOG_INFO, MEMSTRESS_PREFIX "aligned_alloc: %zu bytes, align: %zu,"
|
||||
" ptr: %p\n", nbytes, align, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: debug_realloc
|
||||
****************************************************************************/
|
||||
|
||||
static FAR void *debug_realloc(FAR void *ptr, size_t new_size)
|
||||
{
|
||||
ptr = realloc(ptr, new_size);
|
||||
syslog(LOG_INFO, MEMSTRESS_PREFIX "realloc: %zu bytes, ptr: %p\n",
|
||||
new_size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: init
|
||||
****************************************************************************/
|
||||
|
||||
static void init(FAR struct memorystress_context_s *context, int argc,
|
||||
FAR char *argv[])
|
||||
{
|
||||
FAR struct memorystress_config_s *config;
|
||||
FAR struct memorystress_func_s *func;
|
||||
int ch;
|
||||
|
||||
memset(context, 0, sizeof(struct memorystress_context_s));
|
||||
config = zalloc(sizeof(struct memorystress_config_s));
|
||||
func = zalloc(sizeof(struct memorystress_func_s));
|
||||
if (func == NULL || config == NULL)
|
||||
{
|
||||
free(config);
|
||||
free(func);
|
||||
printf(MEMSTRESS_PREFIX "Malloc struct Failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while ((ch = getopt(argc, argv, "dm:n:t:")) != ERROR)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'd':
|
||||
context->debug = true;
|
||||
break;
|
||||
case 'm':
|
||||
OPTARG_TO_VALUE(config->max_allocsize, size_t);
|
||||
break;
|
||||
case 'n':
|
||||
OPTARG_TO_VALUE(config->nodelen, int);
|
||||
break;
|
||||
case 't':
|
||||
OPTARG_TO_VALUE(context->sleep_us, uint32_t);
|
||||
break;
|
||||
default:
|
||||
show_usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->max_allocsize == 0 || config->nodelen == 0 ||
|
||||
context->sleep_us == 0)
|
||||
{
|
||||
free(config);
|
||||
free(func);
|
||||
show_usage(argv[0]);
|
||||
}
|
||||
|
||||
/* initialization function */
|
||||
|
||||
if (context->debug)
|
||||
{
|
||||
func->malloc = debug_malloc;
|
||||
func->aligned_alloc = debug_aligned_alloc;
|
||||
func->realloc = debug_realloc;
|
||||
func->freefunc = debug_free;
|
||||
}
|
||||
else
|
||||
{
|
||||
func->malloc = malloc;
|
||||
func->aligned_alloc = aligned_alloc;
|
||||
func->realloc = realloc;
|
||||
func->freefunc = free;
|
||||
}
|
||||
|
||||
config->func = func;
|
||||
context->config = config;
|
||||
|
||||
/* init node array */
|
||||
|
||||
context->node_array = zalloc(config->nodelen *
|
||||
sizeof(struct memorystress_node_s));
|
||||
if (context->node_array == NULL)
|
||||
{
|
||||
free(func);
|
||||
free(config);
|
||||
free(context->node_array);
|
||||
printf(MEMSTRESS_PREFIX "Malloc Node Array Failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: init
|
||||
****************************************************************************/
|
||||
|
||||
static void deinit(FAR struct memorystress_context_s*context)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < context->config->nodelen; i++)
|
||||
{
|
||||
free(context->node_array[i].buf);
|
||||
}
|
||||
|
||||
free(context->node_array);
|
||||
free(context->config->func);
|
||||
free(context->config);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: main
|
||||
****************************************************************************/
|
||||
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
struct memorystress_context_s context;
|
||||
|
||||
init(&context, argc, argv);
|
||||
|
||||
printf(MEMSTRESS_PREFIX "testing...\n");
|
||||
|
||||
while (memorystress_iter(&context))
|
||||
{
|
||||
usleep(context.sleep_us);
|
||||
}
|
||||
|
||||
error_result(context.error);
|
||||
|
||||
deinit(&context);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user