diff mbox series

procfs: add syscall statistics

Message ID 20220527110959.54559-1-zhangyuchen.lcr@bytedance.com (mailing list archive)
State New, archived
Headers show
Series procfs: add syscall statistics | expand

Commit Message

Yuchen Zhang May 27, 2022, 11:09 a.m. UTC
Add /proc/syscalls to display percpu syscall count.

We need a less resource-intensive way to count syscall per cpu
for system problem location.

There is a similar utility syscount in the BCC project, but syscount
has a high performance cost.

The following is a comparison on the same machine, using UnixBench
System Call Overhead:

    ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━┓
    ┃ Change        ┃ Unixbench Score ┃ Loss   ┃
    ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━┩
    │ no change     │ 1072.6          │ ---    │
    │ syscall count │ 982.5           │ 8.40%  │
    │ bpf syscount  │ 614.2           │ 42.74% │
    └───────────────┴─────────────────┴────────┘

UnixBench System Call Use sys_gettid to test, this system call only reads
one variable, so the performance penalty seems large. When tested with
fork, the test scores were almost the same.

So the conclusion is that it does not have a significant impact on system
call performance.

This function depends on CONFIG_FTRACE_SYSCALLS because the system call
number is stored in syscall_metadata.

Signed-off-by: Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
---
 Documentation/filesystems/proc.rst       | 28 +++++++++
 arch/arm64/include/asm/syscall_wrapper.h |  2 +-
 arch/s390/include/asm/syscall_wrapper.h  |  4 +-
 arch/x86/include/asm/syscall_wrapper.h   |  2 +-
 fs/proc/Kconfig                          |  7 +++
 fs/proc/Makefile                         |  1 +
 fs/proc/syscall.c                        | 79 ++++++++++++++++++++++++
 include/linux/syscalls.h                 | 51 +++++++++++++--
 8 files changed, 165 insertions(+), 9 deletions(-)
 create mode 100644 fs/proc/syscall.c

Comments

Greg Kroah-Hartman May 27, 2022, 11:49 a.m. UTC | #1
On Fri, May 27, 2022 at 07:09:59PM +0800, Zhang Yuchen wrote:
> Add /proc/syscalls to display percpu syscall count.
> 
> We need a less resource-intensive way to count syscall per cpu
> for system problem location.

Why?

How is this less resource intensive than perf?

> There is a similar utility syscount in the BCC project, but syscount
> has a high performance cost.

What is that cost?

> The following is a comparison on the same machine, using UnixBench
> System Call Overhead:
> 
>     ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━┓
>     ┃ Change        ┃ Unixbench Score ┃ Loss   ┃
>     ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━┩
>     │ no change     │ 1072.6          │ ---    │
>     │ syscall count │ 982.5           │ 8.40%  │
>     │ bpf syscount  │ 614.2           │ 42.74% │
>     └───────────────┴─────────────────┴────────┘

Again, what about perf?

> UnixBench System Call Use sys_gettid to test, this system call only reads
> one variable, so the performance penalty seems large. When tested with
> fork, the test scores were almost the same.
> 
> So the conclusion is that it does not have a significant impact on system
> call performance.

8% is huge for a system-wide decrease in performance.  Who would ever
use this?

> This function depends on CONFIG_FTRACE_SYSCALLS because the system call
> number is stored in syscall_metadata.
> 
> Signed-off-by: Zhang Yuchen <zhangyuchen.lcr@bytedance.com>
> ---
>  Documentation/filesystems/proc.rst       | 28 +++++++++
>  arch/arm64/include/asm/syscall_wrapper.h |  2 +-
>  arch/s390/include/asm/syscall_wrapper.h  |  4 +-
>  arch/x86/include/asm/syscall_wrapper.h   |  2 +-
>  fs/proc/Kconfig                          |  7 +++
>  fs/proc/Makefile                         |  1 +
>  fs/proc/syscall.c                        | 79 ++++++++++++++++++++++++
>  include/linux/syscalls.h                 | 51 +++++++++++++--
>  8 files changed, 165 insertions(+), 9 deletions(-)
>  create mode 100644 fs/proc/syscall.c
> 
> diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
> index 1bc91fb8c321..80394a98a192 100644
> --- a/Documentation/filesystems/proc.rst
> +++ b/Documentation/filesystems/proc.rst
> @@ -686,6 +686,7 @@ files are there, and which are missing.
>   fs 	      File system parameters, currently nfs/exports	(2.4)
>   ide          Directory containing info about the IDE subsystem
>   interrupts   Interrupt usage
> + syscalls     Syscall count for each cpu
>   iomem 	      Memory map					(2.4)
>   ioports      I/O port usage
>   irq 	      Masks for irq to cpu affinity			(2.4)(smp?)
> @@ -1225,6 +1226,33 @@ Provides counts of softirq handlers serviced since boot time, for each CPU.
>      HRTIMER:         0          0          0          0
>  	RCU:      1678       1769       2178       2250
>  
> +syscalls
> +~~~~~~~~
> +
> +Provides counts of syscall since boot time, for each cpu.
> +
> +::
> +
> +    > cat /proc/syscalls
> +               CPU0       CPU1       CPU2       CPU3
> +      0:       3743       3099       3770       3242   sys_read
> +      1:        222        559        822        522   sys_write
> +      2:          0          0          0          0   sys_open
> +      3:       6481      18754      12077       7349   sys_close
> +      4:      11362      11120      11343      10665   sys_newstat
> +      5:       5224      13880       8578       5971   sys_newfstat
> +      6:       1228       1269       1459       1508   sys_newlstat
> +      7:         90         43         64         67   sys_poll
> +      8:       1635       1000       2071       1161   sys_lseek
> +    .... omit the middle line ....
> +    441:          0          0          0          0   sys_epoll_pwait2
> +    442:          0          0          0          0   sys_mount_setattr
> +    443:          0          0          0          0   sys_quotactl_fd
> +    447:          0          0          0          0   sys_memfd_secret
> +    448:          0          0          0          0   sys_process_mrelease
> +    449:          0          0          0          0   sys_futex_waitv
> +    450:          0          0          0          0   sys_set_mempolicy_home_node

So for systems with large numbers of CPUs, these are huge lines?  Have
you tested this on large systems?  If so, how big?

thanks,

greg k-h
Peter Zijlstra May 27, 2022, 12:18 p.m. UTC | #2
On Fri, May 27, 2022 at 07:09:59PM +0800, Zhang Yuchen wrote:
> Add /proc/syscalls to display percpu syscall count.
> 
> We need a less resource-intensive way to count syscall per cpu
> for system problem location.
> 
> There is a similar utility syscount in the BCC project, but syscount
> has a high performance cost.
> 
> The following is a comparison on the same machine, using UnixBench
> System Call Overhead:
> 
>     ┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━┓
>     ┃ Change        ┃ Unixbench Score ┃ Loss   ┃
>     ┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━┩
>     │ no change     │ 1072.6          │ ---    │
>     │ syscall count │ 982.5           │ 8.40%  │
>     │ bpf syscount  │ 614.2           │ 42.74% │
>     └───────────────┴─────────────────┴────────┘
> 
> UnixBench System Call Use sys_gettid to test, this system call only reads
> one variable, so the performance penalty seems large. When tested with
> fork, the test scores were almost the same.
> 
> So the conclusion is that it does not have a significant impact on system
> call performance.
> 
> This function depends on CONFIG_FTRACE_SYSCALLS because the system call
> number is stored in syscall_metadata.

Death by a thousand cuts. 99% of people won't ever use this.

NAK
Alexei Starovoitov May 27, 2022, 2:13 p.m. UTC | #3
On Fri, May 27, 2022 at 4:10 AM Zhang Yuchen
<zhangyuchen.lcr@bytedance.com> wrote:
>
> Add /proc/syscalls to display percpu syscall count.

I second Peter's nack.
We don't add debug features to the production kernel.

> We need a less resource-intensive way to count syscall per cpu
> for system problem location.
>
> There is a similar utility syscount in the BCC project, but syscount
> has a high performance cost.

There are two syscount tools in BCC:
tools/syscount
libbpf-tools/syscount

Which one has this 42% overhead?

The former tool is obsolete though.
It was written in the days when bpf had 1/10 of
the features it has today.
Both tools can be optimized.
They attach to raw_syscalls tracepoint.
tracepoints are not cheap.
In terms of overhead:
tracepoint > raw_tracepoint > fentry.
bpf can attach to all three.

Please profile libbpf-tools/syscount tool
with perf and unixbench, understand where overhead
comes from and then optimize the tool.
kernel test robot May 27, 2022, 2:23 p.m. UTC | #4
Hi Zhang,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on next-20220527]
[cannot apply to akpm-mm/mm-everything arm64/for-next/core s390/features tip/x86/core v5.18]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Zhang-Yuchen/procfs-add-syscall-statistics/20220527-191241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 7e284070abe53d448517b80493863595af4ab5f0
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20220527/202205272216.w7dE4biW-lkp@intel.com/config)
compiler: arceb-elf-gcc (GCC) 11.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/979bf5b1b085588caab1cbdce55e40e823c12db9
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Zhang-Yuchen/procfs-add-syscall-statistics/20220527-191241
        git checkout 979bf5b1b085588caab1cbdce55e40e823c12db9
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=arc SHELL=/bin/bash fs/proc/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> fs/proc/syscall.c:13:5: warning: no previous prototype for 'show_syscalls' [-Wmissing-prototypes]
      13 | int show_syscalls(struct seq_file *p, void *v)
         |     ^~~~~~~~~~~~~


vim +/show_syscalls +13 fs/proc/syscall.c

    12	
  > 13	int show_syscalls(struct seq_file *p, void *v)
    14	{
    15		int i = *(loff_t *)v, j;
    16		static int prec;
    17		const char *syscall_name = get_syscall_name(i);
    18	
    19		if (i > NR_syscalls)
    20			return 0;
    21	
    22		/* print header and calculate the width of the first column */
    23		if (i == 0) {
    24			for (prec = 3, j = 1000; prec < 10 && j <= NR_syscalls; ++prec)
    25				j *= 10;
    26			seq_printf(p, "%*s", prec + 8, "");
    27			for_each_online_cpu(j)
    28				seq_printf(p, "CPU%-8d", j);
    29			seq_putc(p, '\n');
    30		}
    31	
    32		if (syscall_name == NULL)
    33			return 0;
    34	
    35		seq_printf(p, "%*d: ", prec, i);
    36		for_each_online_cpu(j)
    37			seq_printf(p, "%10llu ",
    38				   per_cpu(__per_cpu_syscall_count, j)[i]);
    39		seq_printf(p, "  %s", syscall_name);
    40		seq_putc(p, '\n');
    41	
    42		return 0;
    43	}
    44
kernel test robot May 27, 2022, 5 p.m. UTC | #5
Hi Zhang,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on next-20220527]
[cannot apply to akpm-mm/mm-everything arm64/for-next/core s390/features tip/x86/core v5.18]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/intel-lab-lkp/linux/commits/Zhang-Yuchen/procfs-add-syscall-statistics/20220527-191241
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 7e284070abe53d448517b80493863595af4ab5f0
config: csky-randconfig-r002-20220526 (https://download.01.org/0day-ci/archive/20220528/202205280044.z43jIWts-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 11.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/979bf5b1b085588caab1cbdce55e40e823c12db9
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Zhang-Yuchen/procfs-add-syscall-statistics/20220527-191241
        git checkout 979bf5b1b085588caab1cbdce55e40e823c12db9
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=csky SHELL=/bin/bash arch/csky/kernel/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> arch/csky/kernel/syscall_table.c:11:14: error: conflicting types for 'sys_call_table'; have 'void * const[451]'
      11 | void * const sys_call_table[__NR_syscalls] __page_aligned_data = {
         |              ^~~~~~~~~~~~~~
   In file included from include/linux/syscalls.h:89,
                    from arch/csky/kernel/syscall_table.c:4:
   arch/csky/include/asm/syscall.h:11:14: note: previous declaration of 'sys_call_table' with type 'void *[]'
      11 | extern void *sys_call_table[];
         |              ^~~~~~~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:29:37: note: in expansion of macro '__SYSCALL'
      29 | #define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys)
         |                                     ^~~~~~~~~
   include/uapi/asm-generic/unistd.h:34:1: note: in expansion of macro '__SC_COMP'
      34 | __SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: note: (near initialization for 'sys_call_table[0]')
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:29:37: note: in expansion of macro '__SYSCALL'
      29 | #define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys)
         |                                     ^~~~~~~~~
   include/uapi/asm-generic/unistd.h:34:1: note: in expansion of macro '__SC_COMP'
      34 | __SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:36:1: note: in expansion of macro '__SYSCALL'
      36 | __SYSCALL(__NR_io_destroy, sys_io_destroy)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: note: (near initialization for 'sys_call_table[1]')
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:36:1: note: in expansion of macro '__SYSCALL'
      36 | __SYSCALL(__NR_io_destroy, sys_io_destroy)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:29:37: note: in expansion of macro '__SYSCALL'
      29 | #define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys)
         |                                     ^~~~~~~~~
   include/uapi/asm-generic/unistd.h:38:1: note: in expansion of macro '__SC_COMP'
      38 | __SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: note: (near initialization for 'sys_call_table[2]')
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:29:37: note: in expansion of macro '__SYSCALL'
      29 | #define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys)
         |                                     ^~~~~~~~~
   include/uapi/asm-generic/unistd.h:38:1: note: in expansion of macro '__SC_COMP'
      38 | __SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:40:1: note: in expansion of macro '__SYSCALL'
      40 | __SYSCALL(__NR_io_cancel, sys_io_cancel)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: note: (near initialization for 'sys_call_table[3]')
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:40:1: note: in expansion of macro '__SYSCALL'
      40 | __SYSCALL(__NR_io_cancel, sys_io_cancel)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:20:34: note: in expansion of macro '__SYSCALL'
      20 | #define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32)
         |                                  ^~~~~~~~~
   include/uapi/asm-generic/unistd.h:43:1: note: in expansion of macro '__SC_3264'
      43 | __SC_3264(__NR_io_getevents, sys_io_getevents_time32, sys_io_getevents)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: note: (near initialization for 'sys_call_table[4]')
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:20:34: note: in expansion of macro '__SYSCALL'
      20 | #define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32)
         |                                  ^~~~~~~~~
   include/uapi/asm-generic/unistd.h:43:1: note: in expansion of macro '__SC_3264'
      43 | __SC_3264(__NR_io_getevents, sys_io_getevents_time32, sys_io_getevents)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:48:1: note: in expansion of macro '__SYSCALL'
      48 | __SYSCALL(__NR_setxattr, sys_setxattr)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: note: (near initialization for 'sys_call_table[5]')
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^
   include/uapi/asm-generic/unistd.h:48:1: note: in expansion of macro '__SYSCALL'
      48 | __SYSCALL(__NR_setxattr, sys_setxattr)
         | ^~~~~~~~~
   arch/csky/kernel/syscall_table.c:8:35: warning: initialized field overwritten [-Woverride-init]
       8 | #define __SYSCALL(nr, call)[nr] = (call),
         |                                   ^


vim +11 arch/csky/kernel/syscall_table.c

4859bfca11c7d6 Guo Ren 2018-09-05   9  
4859bfca11c7d6 Guo Ren 2018-09-05  10  #define sys_fadvise64_64 sys_csky_fadvise64_64
4859bfca11c7d6 Guo Ren 2018-09-05 @11  void * const sys_call_table[__NR_syscalls] __page_aligned_data = {
diff mbox series

Patch

diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst
index 1bc91fb8c321..80394a98a192 100644
--- a/Documentation/filesystems/proc.rst
+++ b/Documentation/filesystems/proc.rst
@@ -686,6 +686,7 @@  files are there, and which are missing.
  fs 	      File system parameters, currently nfs/exports	(2.4)
  ide          Directory containing info about the IDE subsystem
  interrupts   Interrupt usage
+ syscalls     Syscall count for each cpu
  iomem 	      Memory map					(2.4)
  ioports      I/O port usage
  irq 	      Masks for irq to cpu affinity			(2.4)(smp?)
@@ -1225,6 +1226,33 @@  Provides counts of softirq handlers serviced since boot time, for each CPU.
     HRTIMER:         0          0          0          0
 	RCU:      1678       1769       2178       2250
 
+syscalls
+~~~~~~~~
+
+Provides counts of syscall since boot time, for each cpu.
+
+::
+
+    > cat /proc/syscalls
+               CPU0       CPU1       CPU2       CPU3
+      0:       3743       3099       3770       3242   sys_read
+      1:        222        559        822        522   sys_write
+      2:          0          0          0          0   sys_open
+      3:       6481      18754      12077       7349   sys_close
+      4:      11362      11120      11343      10665   sys_newstat
+      5:       5224      13880       8578       5971   sys_newfstat
+      6:       1228       1269       1459       1508   sys_newlstat
+      7:         90         43         64         67   sys_poll
+      8:       1635       1000       2071       1161   sys_lseek
+    .... omit the middle line ....
+    441:          0          0          0          0   sys_epoll_pwait2
+    442:          0          0          0          0   sys_mount_setattr
+    443:          0          0          0          0   sys_quotactl_fd
+    447:          0          0          0          0   sys_memfd_secret
+    448:          0          0          0          0   sys_process_mrelease
+    449:          0          0          0          0   sys_futex_waitv
+    450:          0          0          0          0   sys_set_mempolicy_home_node
+
 1.3 Networking info in /proc/net
 --------------------------------
 
diff --git a/arch/arm64/include/asm/syscall_wrapper.h b/arch/arm64/include/asm/syscall_wrapper.h
index b383b4802a7b..d9ec21df4c44 100644
--- a/arch/arm64/include/asm/syscall_wrapper.h
+++ b/arch/arm64/include/asm/syscall_wrapper.h
@@ -66,7 +66,7 @@  struct pt_regs;
 	}									\
 	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
 
-#define SYSCALL_DEFINE0(sname)							\
+#define __SYSCALL_DEFINE0(sname)							\
 	SYSCALL_METADATA(_##sname, 0);						\
 	asmlinkage long __arm64_sys_##sname(const struct pt_regs *__unused);	\
 	ALLOW_ERROR_INJECTION(__arm64_sys_##sname, ERRNO);			\
diff --git a/arch/s390/include/asm/syscall_wrapper.h b/arch/s390/include/asm/syscall_wrapper.h
index fde7e6b1df48..f8d7d9010de2 100644
--- a/arch/s390/include/asm/syscall_wrapper.h
+++ b/arch/s390/include/asm/syscall_wrapper.h
@@ -77,7 +77,7 @@ 
 	ALLOW_ERROR_INJECTION(__s390_compat_sys_##sname, ERRNO);	\
 	long __s390_compat_sys_##sname(void)
 
-#define SYSCALL_DEFINE0(sname)						\
+#define __SYSCALL_DEFINE0(sname)						\
 	SYSCALL_METADATA(_##sname, 0);					\
 	long __s390x_sys_##sname(void);					\
 	ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO);		\
@@ -128,7 +128,7 @@ 
 
 #define __S390_SYS_STUBx(x, fullname, name, ...)
 
-#define SYSCALL_DEFINE0(sname)						\
+#define __SYSCALL_DEFINE0(sname)						\
 	SYSCALL_METADATA(_##sname, 0);					\
 	long __s390x_sys_##sname(void);					\
 	ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO);		\
diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h
index 59358d1bf880..1f16436c13bd 100644
--- a/arch/x86/include/asm/syscall_wrapper.h
+++ b/arch/x86/include/asm/syscall_wrapper.h
@@ -246,7 +246,7 @@  extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
  * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI()
  * macros to work correctly.
  */
-#define SYSCALL_DEFINE0(sname)						\
+#define __SYSCALL_DEFINE0(sname)						\
 	SYSCALL_METADATA(_##sname, 0);					\
 	static long __do_sys_##sname(const struct pt_regs *__unused);	\
 	__X64_SYS_STUB0(sname)						\
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index c930001056f9..9e5fa75ebd2a 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -100,6 +100,13 @@  config PROC_CHILDREN
 	  Say Y if you are running any user-space software which takes benefit from
 	  this interface. For example, rkt is such a piece of software.
 
+config PROC_SYSCALLS
+	bool "Include /proc/syscalls file" if EXPERT
+	depends on PROC_FS && FTRACE_SYSCALLS
+	default n
+	help
+	  Provides a file that shows the number of syscall on each cpu.
+
 config PROC_PID_ARCH_STATUS
 	def_bool n
 	depends on PROC_FS
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index bd08616ed8ba..f381a7aa90ae 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -31,6 +31,7 @@  proc-$(CONFIG_PROC_SYSCTL)	+= proc_sysctl.o
 proc-$(CONFIG_NET)		+= proc_net.o
 proc-$(CONFIG_PROC_KCORE)	+= kcore.o
 proc-$(CONFIG_PROC_VMCORE)	+= vmcore.o
+proc-$(CONFIG_PROC_SYSCALLS)	+= syscall.o
 proc-$(CONFIG_PRINTK)	+= kmsg.o
 proc-$(CONFIG_PROC_PAGE_MONITOR)	+= page.o
 proc-$(CONFIG_BOOT_CONFIG)	+= bootconfig.o
diff --git a/fs/proc/syscall.c b/fs/proc/syscall.c
new file mode 100644
index 000000000000..88196b16f430
--- /dev/null
+++ b/fs/proc/syscall.c
@@ -0,0 +1,79 @@ 
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/syscall.h>
+
+DEFINE_PER_CPU(u64 [NR_syscalls], __per_cpu_syscall_count);
+
+extern const char *get_syscall_name(int syscall_nr);
+
+int show_syscalls(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *)v, j;
+	static int prec;
+	const char *syscall_name = get_syscall_name(i);
+
+	if (i > NR_syscalls)
+		return 0;
+
+	/* print header and calculate the width of the first column */
+	if (i == 0) {
+		for (prec = 3, j = 1000; prec < 10 && j <= NR_syscalls; ++prec)
+			j *= 10;
+		seq_printf(p, "%*s", prec + 8, "");
+		for_each_online_cpu(j)
+			seq_printf(p, "CPU%-8d", j);
+		seq_putc(p, '\n');
+	}
+
+	if (syscall_name == NULL)
+		return 0;
+
+	seq_printf(p, "%*d: ", prec, i);
+	for_each_online_cpu(j)
+		seq_printf(p, "%10llu ",
+			   per_cpu(__per_cpu_syscall_count, j)[i]);
+	seq_printf(p, "  %s", syscall_name);
+	seq_putc(p, '\n');
+
+	return 0;
+}
+
+/*
+ * /proc/syscalls
+ */
+static void *int_seq_start(struct seq_file *f, loff_t *pos)
+{
+	return (*pos <= NR_syscalls) ? pos : NULL;
+}
+
+static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	(*pos)++;
+	if (*pos > NR_syscalls)
+		return NULL;
+	return pos;
+}
+
+static void int_seq_stop(struct seq_file *f, void *v)
+{
+	/* Nothing to do */
+}
+
+static const struct seq_operations int_seq_ops = {
+	.start = int_seq_start,
+	.next  = int_seq_next,
+	.stop  = int_seq_stop,
+	.show  = show_syscalls
+};
+
+static int __init proc_syscall_init(void)
+{
+	proc_create_seq("syscalls", 0, NULL, &int_seq_ops);
+	return 0;
+}
+
+fs_initcall(proc_syscall_init);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a34b0f9a9972..a3d50b8d39d8 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -86,6 +86,7 @@  enum landlock_rule_type;
 #include <linux/key.h>
 #include <linux/personality.h>
 #include <trace/syscall.h>
+#include <asm/syscall.h>
 
 #ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
 /*
@@ -206,8 +207,8 @@  static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
 }
 #endif
 
-#ifndef SYSCALL_DEFINE0
-#define SYSCALL_DEFINE0(sname)					\
+#ifndef __SYSCALL_DEFINE0
+#define __SYSCALL_DEFINE0(sname)					\
 	SYSCALL_METADATA(_##sname, 0);				\
 	asmlinkage long sys_##sname(void);			\
 	ALLOW_ERROR_INJECTION(sys_##sname, ERRNO);		\
@@ -223,9 +224,49 @@  static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
 
 #define SYSCALL_DEFINE_MAXARGS	6
 
-#define SYSCALL_DEFINEx(x, sname, ...)				\
-	SYSCALL_METADATA(sname, x, __VA_ARGS__)			\
-	__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
+#ifdef CONFIG_PROC_SYSCALLS
+DECLARE_PER_CPU(u64[], __per_cpu_syscall_count);
+
+#define SYSCALL_COUNT_DECLAREx(sname, x, ...) \
+	static inline long __count_sys##sname(__MAP(x, __SC_DECL, __VA_ARGS__));
+
+#define __SYSCALL_COUNT(syscall_nr) \
+	this_cpu_inc(__per_cpu_syscall_count[(syscall_nr)])
+
+#define SYSCALL_COUNT_FUNCx(sname, x, ...)					\
+	{									\
+		__SYSCALL_COUNT(__syscall_meta_##sname.syscall_nr);		\
+		return __count_sys##sname(__MAP(x, __SC_CAST, __VA_ARGS__));	\
+	}									\
+	static inline long __count_sys##sname(__MAP(x, __SC_DECL, __VA_ARGS__))
+
+#define SYSCALL_COUNT_DECLARE0(sname) \
+	static inline long __count_sys_##sname(void);
+
+#define SYSCALL_COUNT_FUNC0(sname)					\
+	{								\
+		__SYSCALL_COUNT(__syscall_meta__##sname.syscall_nr);	\
+		return __count_sys_##sname();				\
+	}								\
+	static inline long __count_sys_##sname(void)
+
+#else
+#define SYSCALL_COUNT_DECLAREx(sname, x, ...)
+#define SYSCALL_COUNT_FUNCx(sname, x, ...)
+#define SYSCALL_COUNT_DECLARE0(sname)
+#define SYSCALL_COUNT_FUNC0(sname)
+#endif
+
+#define SYSCALL_DEFINEx(x, sname, ...)			\
+	SYSCALL_METADATA(sname, x, __VA_ARGS__)		\
+	SYSCALL_COUNT_DECLAREx(sname, x, __VA_ARGS__)	\
+	__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)	\
+	SYSCALL_COUNT_FUNCx(sname, x, __VA_ARGS__)
+
+#define SYSCALL_DEFINE0(sname)		\
+	SYSCALL_COUNT_DECLARE0(sname)	\
+	__SYSCALL_DEFINE0(sname)	\
+	SYSCALL_COUNT_FUNC0(sname)
 
 #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)