This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 4a78dedbae454913af67ca75a096f60a92886a47
Author: chenrun1 <chenr...@xiaomi.com>
AuthorDate: Mon Jul 10 14:40:58 2023 +0800

    memorystress:For pressure detection of memory stability
    
    Signed-off-by: chenrun1 <chenr...@xiaomi.com>
---
 system/memstress/Kconfig             |  29 ++
 system/memstress/Make.defs           |  23 ++
 system/memstress/Makefile            |  32 +++
 system/memstress/memorystress_main.c | 509 +++++++++++++++++++++++++++++++++++
 4 files changed, 593 insertions(+)

diff --git a/system/memstress/Kconfig b/system/memstress/Kconfig
new file mode 100644
index 000000000..b0e592425
--- /dev/null
+++ b/system/memstress/Kconfig
@@ -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
diff --git a/system/memstress/Make.defs b/system/memstress/Make.defs
new file mode 100644
index 000000000..0463fd55a
--- /dev/null
+++ b/system/memstress/Make.defs
@@ -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
diff --git a/system/memstress/Makefile b/system/memstress/Makefile
new file mode 100644
index 000000000..9e9f6a665
--- /dev/null
+++ b/system/memstress/Makefile
@@ -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
diff --git a/system/memstress/memorystress_main.c 
b/system/memstress/memorystress_main.c
new file mode 100644
index 000000000..802b1b528
--- /dev/null
+++ b/system/memstress/memorystress_main.c
@@ -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;
+}

Reply via email to