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.git

commit d932e0af2a97dee406cd9156425da2bcaac7e655
Author: anjiahao <[email protected]>
AuthorDate: Fri Oct 27 21:57:33 2023 +0800

    sched/procfs:use instrument to statistics run time max stack
    
    Usage:
    1. CONFIG_FS_PROCFS_MAX_STACK_RECORD > 0, such as 32,
    2. add '-finstrument-functions' to CFLAGS for What you want to check
       stack.
    3. mount porcfs
    4. cat /proc/<pid>/stack will print backtace & size
    
    Signed-off-by: anjiahao <[email protected]>
---
 arch/sim/include/irq.h          |   1 +
 fs/procfs/fs_procfsproc.c       |  53 +++++++++++++++++++
 include/nuttx/compiler.h        |   9 ++++
 include/nuttx/sched.h           |  11 ++++
 sched/Kconfig                   |  13 +++++
 sched/Makefile                  |   1 +
 sched/init/nx_start.c           |   5 ++
 sched/instrument/CMakeLists.txt |  27 ++++++++++
 sched/instrument/Make.defs      |  30 +++++++++++
 sched/instrument/instrument.c   |  58 +++++++++++++++++++++
 sched/instrument/instrument.h   |  44 ++++++++++++++++
 sched/instrument/stack_record.c | 112 ++++++++++++++++++++++++++++++++++++++++
 12 files changed, 364 insertions(+)

diff --git a/arch/sim/include/irq.h b/arch/sim/include/irq.h
index 05942e5232..e5474e15fa 100644
--- a/arch/sim/include/irq.h
+++ b/arch/sim/include/irq.h
@@ -146,6 +146,7 @@ static inline uintptr_t up_getsp(void)
  *
  ****************************************************************************/
 
+noinstrument_function
 static inline bool up_interrupt_context(void)
 {
 #ifdef CONFIG_SMP
diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c
index d5f3532de2..0995985855 100644
--- a/fs/procfs/fs_procfsproc.c
+++ b/fs/procfs/fs_procfsproc.c
@@ -986,6 +986,9 @@ static ssize_t proc_stack(FAR struct proc_file_s *procfile,
   size_t linesize;
   size_t copysize;
   size_t totalsize;
+#if CONFIG_SCHED_STACK_RECORD > 0
+  int i;
+#endif
 
   remaining = buflen;
   totalsize = 0;
@@ -1033,6 +1036,56 @@ static ssize_t proc_stack(FAR struct proc_file_s 
*procfile,
   buffer    += copysize;
   remaining -= copysize;
 
+#if CONFIG_SCHED_STACK_RECORD > 0
+  linesize   = procfs_snprintf(procfile->line, STATUS_LINELEN, "%-12s%zu\n",
+                              "StackMax: ",
+                              tcb->stack_base_ptr +
+                              tcb->adj_stack_size - tcb->sp_deepest);
+  copysize   = procfs_memcpy(procfile->line, linesize, buffer, remaining,
+                             &offset);
+
+  totalsize += copysize;
+  buffer    += copysize;
+  remaining -= copysize;
+
+  linesize   = procfs_snprintf(procfile->line, STATUS_LINELEN, "%-12s%-s\n",
+                               "Size", "Backtrace");
+  copysize   = procfs_memcpy(procfile->line, linesize, buffer, remaining,
+                             &offset);
+
+  totalsize += copysize;
+  buffer    += copysize;
+  remaining -= copysize;
+
+  for (i = tcb->level_deepest - 1; i > 0; i--)
+    {
+      linesize = procfs_snprintf(procfile->line, STATUS_LINELEN,
+                                 "%-12zu%-pS\n",
+                                 tcb->stackrecord_sp_deepest[i - 1] -
+                                 tcb->stackrecord_sp_deepest[i],
+                                 tcb->stackrecord_pc_deepest[i]);
+      copysize = procfs_memcpy(procfile->line, linesize, buffer, remaining,
+                               &offset);
+      totalsize += copysize;
+      buffer    += copysize;
+      remaining -= copysize;
+    }
+
+  if (tcb->caller_deepest)
+    {
+      linesize = procfs_snprintf(procfile->line, STATUS_LINELEN,
+                                 "Warning stack record buffer too small\n"
+                                 "Max: %u Overflow: %zu\n",
+                                 CONFIG_SCHED_STACK_RECORD,
+                                 tcb->caller_deepest);
+      copysize = procfs_memcpy(procfile->line, linesize, buffer, remaining,
+                               &offset);
+      totalsize += copysize;
+      buffer    += copysize;
+      remaining -= copysize;
+    }
+#endif
+
 #ifdef CONFIG_STACK_COLORATION
   if (totalsize >= buflen)
     {
diff --git a/include/nuttx/compiler.h b/include/nuttx/compiler.h
index 74edd9f212..222f37c12c 100644
--- a/include/nuttx/compiler.h
+++ b/include/nuttx/compiler.h
@@ -251,6 +251,10 @@
 
 #  define noinstrument_function __attribute__((no_instrument_function))
 
+/* The nooptimiziation_function attribute no optimize */
+
+#  define nooptimiziation_function __attribute__((optimize(0)))
+
 /* The nosanitize_address attribute informs GCC don't sanitize it */
 
 #  define nosanitize_address __attribute__((no_sanitize_address))
@@ -555,6 +559,7 @@
 #  define always_inline_function
 #  define noinline_function
 #  define noinstrument_function
+#  define nooptimiziation_function
 #  define nosanitize_address
 #  define nosanitize_undefined
 #  define nostackprotect_function
@@ -698,6 +703,7 @@
 #  define always_inline_function
 #  define noinline_function
 #  define noinstrument_function
+#  define nooptimiziation_function
 #  define nosanitize_address
 #  define nosanitize_undefined
 #  define nostackprotect_function
@@ -809,6 +815,7 @@
 #  define always_inline_function
 #  define noinline_function
 #  define noinstrument_function
+#  define nooptimiziation_function
 #  define nosanitize_address
 #  define nosanitize_undefined
 #  define nostackprotect_function
@@ -899,6 +906,7 @@
 #  define always_inline_function
 #  define noinline_function
 #  define noinstrument_function
+#  define nooptimiziation_function
 #  define nosanitize_address
 #  define nosanitize_undefined
 #  define nostackprotect_function
@@ -964,6 +972,7 @@
 #  define always_inline_function
 #  define noinline_function
 #  define noinstrument_function
+#  define nooptimiziation_function
 #  define nosanitize_address
 #  define nosanitize_undefined
 #  define nostackprotect_function
diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index 3154a7d61a..a80af294e0 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -645,6 +645,17 @@ struct tcb_s
 #if CONFIG_TASK_NAME_SIZE > 0
   char name[CONFIG_TASK_NAME_SIZE + 1];  /* Task name (with NUL terminator  */
 #endif
+
+#if CONFIG_SCHED_STACK_RECORD > 0
+  FAR void *stackrecord_pc[CONFIG_SCHED_STACK_RECORD];
+  FAR void *stackrecord_sp[CONFIG_SCHED_STACK_RECORD];
+  FAR void *stackrecord_pc_deepest[CONFIG_SCHED_STACK_RECORD];
+  FAR void *stackrecord_sp_deepest[CONFIG_SCHED_STACK_RECORD];
+  FAR void *sp_deepest;
+  size_t caller_deepest;
+  size_t level_deepest;
+  size_t level;
+#endif
 };
 
 /* struct task_tcb_s ********************************************************/
diff --git a/sched/Kconfig b/sched/Kconfig
index 1746649a41..40512719b6 100644
--- a/sched/Kconfig
+++ b/sched/Kconfig
@@ -1221,6 +1221,19 @@ config SCHED_INSTRUMENTATION_FUNCTION
 endif # SCHED_INSTRUMENTATION
 endmenu # Performance Monitoring
 
+menu "System Auto Instrumentation"
+
+config SCHED_STACK_RECORD
+       int "Maximum stack backtrace to record"
+       default 0
+       ---help---
+               Specifies the maximum number of stack backtrace to record in the
+               TCB.  Useful if scheduler instrumentation is selected.  Set to 
zero
+               to disable.Through instrumentation, record the backtrace at
+               the deepest point in the stack.
+
+endmenu
+
 menu "Files and I/O"
 
 config DEV_CONSOLE
diff --git a/sched/Makefile b/sched/Makefile
index ccd723f9d6..fcddb0c4c1 100644
--- a/sched/Makefile
+++ b/sched/Makefile
@@ -25,6 +25,7 @@ include clock/Make.defs
 include environ/Make.defs
 include group/Make.defs
 include init/Make.defs
+include instrument/Make.defs
 include irq/Make.defs
 include misc/Make.defs
 include mqueue/Make.defs
diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c
index 176c010999..98a5f1cfb7 100644
--- a/sched/init/nx_start.c
+++ b/sched/init/nx_start.c
@@ -56,6 +56,7 @@
 #include "irq/irq.h"
 #include "group/group.h"
 #include "init/init.h"
+#include "instrument/instrument.h"
 #include "tls/tls.h"
 
 /****************************************************************************
@@ -564,6 +565,10 @@ void nx_start(void)
 
   sched_lock();
 
+  /* Initialize the instrument function */
+
+  instrument_initialize();
+
   /* Initialize the file system (needed to support device drivers) */
 
   fs_initialize();
diff --git a/sched/instrument/CMakeLists.txt b/sched/instrument/CMakeLists.txt
new file mode 100644
index 0000000000..08c4f1a34c
--- /dev/null
+++ b/sched/instrument/CMakeLists.txt
@@ -0,0 +1,27 @@
+# 
##############################################################################
+# sched/instrument/CMakeLists.txt
+#
+# 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.
+#
+# 
##############################################################################
+
+set(SRCS instrument.c)
+
+if(NOT "${CONFIG_SCHED_STACK_RECORD}" STREQUAL "0")
+  list(APPEND SRCS stack_record.c)
+endif()
+
+target_sources(sched PRIVATE ${SRCS})
diff --git a/sched/instrument/Make.defs b/sched/instrument/Make.defs
new file mode 100644
index 0000000000..7f86322c8f
--- /dev/null
+++ b/sched/instrument/Make.defs
@@ -0,0 +1,30 @@
+############################################################################
+# sched/instrument/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.
+#
+############################################################################
+
+CSRCS += instrument.c
+
+ifneq ($(CONFIG_SCHED_STACK_RECORD),0)
+CSRCS += stack_record.c
+endif
+
+# Include instrument build support
+
+DEPPATH += --dep-path instrument
+VPATH += :instrument
diff --git a/sched/instrument/instrument.c b/sched/instrument/instrument.c
new file mode 100644
index 0000000000..a9581fd26e
--- /dev/null
+++ b/sched/instrument/instrument.c
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * sched/instrument/instrument.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/instrument.h>
+
+/****************************************************************************
+ * External Definitions
+ ****************************************************************************/
+
+#if CONFIG_SCHED_STACK_RECORD > 0
+extern struct instrument_s g_stack_record;
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: instrument_initialize
+ *
+ * Description:
+ *   This function is called to initialize all the instrument functions
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Does not return.
+ *
+ ****************************************************************************/
+
+void instrument_initialize(void)
+{
+#if CONFIG_SCHED_STACK_RECORD > 0
+  instrument_register(&g_stack_record);
+#endif
+}
diff --git a/sched/instrument/instrument.h b/sched/instrument/instrument.h
new file mode 100644
index 0000000000..10a50082d8
--- /dev/null
+++ b/sched/instrument/instrument.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+ * sched/instrument/instrument.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __SCHED_INSTRUMENT_INSTRUMENT_H
+#define __SCHED_INSTRUMENT_INSTRUMENT_H
+
+/****************************************************************************
+ * Public Functions prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: instrument_initialize
+ *
+ * Description:
+ *   This function is called to initialize all the instrument functions
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Does not return.
+ *
+ ****************************************************************************/
+
+void instrument_initialize(void);
+
+#endif
diff --git a/sched/instrument/stack_record.c b/sched/instrument/stack_record.c
new file mode 100644
index 0000000000..69b1a0ffe1
--- /dev/null
+++ b/sched/instrument/stack_record.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * sched/instrument/stack_record.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/instrument.h>
+#include <sys/param.h>
+
+#include "sched/sched.h"
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void stack_record_enter(FAR void *this_fn, FAR void *call_site,
+                               FAR void *arg) noinstrument_function
+                               nooptimiziation_function;
+static void stack_record_leave(FAR void *this_fn, FAR void *call_site,
+                               FAR void *arg) noinstrument_function
+                               nooptimiziation_function;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+struct instrument_s g_stack_record =
+{
+  .enter = stack_record_enter,
+  .leave = stack_record_leave
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stack_statistics
+ ****************************************************************************/
+
+static void stack_record_enter(FAR void *this_fn, FAR void *call_site,
+                               FAR void *arg)
+{
+  FAR struct tcb_s *tcb = running_task();
+  FAR void *sp = &tcb;
+  size_t i;
+
+  if (tcb == NULL || sp < tcb->stack_base_ptr ||
+      sp >= tcb->stack_base_ptr + tcb->adj_stack_size)
+    {
+      return;
+    }
+
+  if (tcb->level < CONFIG_SCHED_STACK_RECORD)
+    {
+      tcb->stackrecord_sp[tcb->level] = sp;
+      tcb->stackrecord_pc[tcb->level++] = this_fn;
+    }
+  else if (tcb->caller_deepest < ++tcb->level)
+    {
+      tcb->caller_deepest = tcb->level;
+    }
+
+  if (tcb->sp_deepest == NULL || sp < tcb->sp_deepest)
+    {
+      tcb->level_deepest = MIN(tcb->level, CONFIG_SCHED_STACK_RECORD);
+      for (i = 0; i < tcb->level_deepest; i++)
+        {
+          tcb->stackrecord_pc_deepest[i] = tcb->stackrecord_pc[i];
+          tcb->stackrecord_sp_deepest[i] = tcb->stackrecord_sp[i];
+        }
+
+      tcb->sp_deepest = sp;
+    }
+}
+
+/****************************************************************************
+ * Name: stackrecord_leave
+ ****************************************************************************/
+
+static void stack_record_leave(FAR void *this_fn, FAR void *call_site,
+                               FAR void *arg)
+{
+  FAR struct tcb_s *tcb = running_task();
+  FAR void *sp = &tcb;
+
+  if (tcb == NULL || tcb->level == 0 || sp < tcb->stack_base_ptr ||
+      sp >= tcb->stack_base_ptr + tcb->adj_stack_size)
+    {
+      return;
+    }
+
+  tcb->level--;
+}

Reply via email to