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--; +}
