Skip to content

Commit 6cbaa23

Browse files
committed
fs: Add Kernel-level VFS Performance Profiler
Signed-off-by: Sumit6307 <sumitkesar6307@gmail.com>
1 parent ff1fec2 commit 6cbaa23

12 files changed

Lines changed: 346 additions & 0 deletions

File tree

fs/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55

66
comment "File system configuration"
77

8+
config FS_PROFILER
9+
bool "VFS Performance Profiler"
10+
default n
11+
---help---
12+
Enable nanosecond/microsecond-level profiling for the Virtual File
13+
System (VFS) operations (open, close, read, write). The profile stats
14+
can be read via /proc/fs/profile if PROCFS is enabled.
15+
816
config DISABLE_MOUNTPOINT
917
bool "Disable support for mount points"
1018
default n

fs/procfs/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ config FS_PROCFS_EXCLUDE_VERSION
148148
bool "Exclude version"
149149
default DEFAULT_SMALL
150150

151+
config FS_PROCFS_EXCLUDE_PROFILE
152+
bool "Exclude fs/profile information"
153+
depends on FS_PROFILER
154+
default DEFAULT_SMALL
155+
---help---
156+
Causes the VFS profile information to be excluded from the procfs
157+
system.
158+
151159
config FS_PROCFS_INCLUDE_PRESSURE
152160
bool "Include memory pressure notification"
153161
default n

fs/procfs/Make.defs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ ifeq ($(CONFIG_FS_PROCFS_INCLUDE_PRESSURE),y)
3232
CSRCS += fs_procfspressure.c
3333
endif
3434

35+
ifneq ($(CONFIG_FS_PROCFS_EXCLUDE_PROFILE),y)
36+
ifeq ($(CONFIG_FS_PROFILER),y)
37+
CSRCS += fs_procfsprofile.c
38+
endif
39+
endif
40+
3541
# Include procfs build support
3642

3743
DEPPATH += --dep-path procfs

fs/procfs/fs_procfs.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ extern const struct procfs_operations g_thermal_operations;
7474
extern const struct procfs_operations g_uptime_operations;
7575
extern const struct procfs_operations g_version_operations;
7676
extern const struct procfs_operations g_pressure_operations;
77+
#if defined(CONFIG_FS_PROFILER) && \
78+
!defined(CONFIG_FS_PROCFS_EXCLUDE_PROFILE)
79+
extern const struct procfs_operations g_profile_operations;
80+
#endif
7781

7882
/* This is not good. These are implemented in other sub-systems. Having to
7983
* deal with them here is not a good coupling. What is really needed is a
@@ -208,6 +212,10 @@ static const struct procfs_entry_s g_procfs_entries[] =
208212
#ifndef CONFIG_FS_PROCFS_EXCLUDE_VERSION
209213
{ "version", &g_version_operations, PROCFS_FILE_TYPE },
210214
#endif
215+
#if defined(CONFIG_FS_PROFILER) && \
216+
!defined(CONFIG_FS_PROCFS_EXCLUDE_PROFILE)
217+
{ "profile", &g_profile_operations, PROCFS_FILE_TYPE },
218+
#endif
211219
};
212220

213221
#ifdef CONFIG_FS_PROCFS_REGISTER

fs/procfs/fs_procfsprofile.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/****************************************************************************
2+
* fs/procfs/fs_procfsprofile.c
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
/****************************************************************************
24+
* Included Files
25+
****************************************************************************/
26+
27+
#include <nuttx/config.h>
28+
29+
#if defined(CONFIG_FS_PROCFS) && defined(CONFIG_FS_PROFILER) && \
30+
!defined(CONFIG_FS_PROCFS_EXCLUDE_PROFILE)
31+
32+
#include <sys/types.h>
33+
#include <sys/stat.h>
34+
#include <stdio.h>
35+
#include <string.h>
36+
37+
#include <nuttx/fs/fs.h>
38+
#include <nuttx/fs/procfs.h>
39+
#include <nuttx/fs/fs_profile.h>
40+
41+
/****************************************************************************
42+
* Private Functions
43+
****************************************************************************/
44+
45+
static int profile_open(FAR struct file *filep, FAR const char *relpath,
46+
int oflags, mode_t mode)
47+
{
48+
return OK;
49+
}
50+
51+
static int profile_close(FAR struct file *filep)
52+
{
53+
return OK;
54+
}
55+
56+
static ssize_t profile_read(FAR struct file *filep, FAR char *buffer,
57+
size_t buflen)
58+
{
59+
char buf[256];
60+
size_t linesize;
61+
off_t offset = filep->f_pos;
62+
63+
if (offset > 0)
64+
{
65+
return 0;
66+
}
67+
68+
snprintf(buf, sizeof(buf),
69+
"VFS Performance Profile:\n"
70+
" Reads: %10lu (Total time: %llu ns)\n"
71+
" Writes: %10lu (Total time: %llu ns)\n"
72+
" Opens: %10lu (Total time: %llu ns)\n"
73+
" Closes: %10lu (Total time: %llu ns)\n",
74+
(unsigned long)g_vfs_profile.reads,
75+
(unsigned long long)g_vfs_profile.total_read_time,
76+
(unsigned long)g_vfs_profile.writes,
77+
(unsigned long long)g_vfs_profile.total_write_time,
78+
(unsigned long)g_vfs_profile.opens,
79+
(unsigned long long)g_vfs_profile.total_open_time,
80+
(unsigned long)g_vfs_profile.closes,
81+
(unsigned long long)g_vfs_profile.total_close_time);
82+
83+
linesize = strlen(buf);
84+
if (linesize > buflen)
85+
{
86+
linesize = buflen;
87+
}
88+
89+
memcpy(buffer, buf, linesize);
90+
filep->f_pos += linesize;
91+
return linesize;
92+
}
93+
94+
static int profile_dup(FAR const struct file *oldp, FAR struct file *newp)
95+
{
96+
return OK;
97+
}
98+
99+
static int profile_stat(FAR const char *relpath, FAR struct stat *buf)
100+
{
101+
memset(buf, 0, sizeof(struct stat));
102+
buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
103+
return OK;
104+
}
105+
106+
/****************************************************************************
107+
* Public Data
108+
****************************************************************************/
109+
110+
const struct procfs_operations g_profile_operations =
111+
{
112+
profile_open, /* open */
113+
profile_close, /* close */
114+
profile_read, /* read */
115+
NULL, /* write */
116+
NULL, /* poll */
117+
profile_dup, /* dup */
118+
NULL, /* opendir */
119+
NULL, /* closedir */
120+
NULL, /* readdir */
121+
NULL, /* rewinddir */
122+
profile_stat /* stat */
123+
};
124+
125+
#endif
126+

fs/vfs/Make.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ ifeq ($(CONFIG_SIGNAL_FD),y)
6565
CSRCS += fs_signalfd.c
6666
endif
6767

68+
ifeq ($(CONFIG_FS_PROFILER),y)
69+
CSRCS += fs_profile.c
70+
endif
71+
6872
# Include vfs build support
6973

7074
DEPPATH += --dep-path vfs

fs/vfs/fs_close.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "inode/inode.h"
4343
#include "sched/sched.h"
4444
#include "vfs.h"
45+
#include <nuttx/fs/fs_profile.h>
4546

4647
/****************************************************************************
4748
* Private Functions
@@ -119,9 +120,19 @@ int file_close(FAR struct file *filep)
119120

120121
if (inode->u.i_ops && inode->u.i_ops->close)
121122
{
123+
#ifdef CONFIG_FS_PROFILER
124+
struct timespec start_time;
125+
VFS_PROFILE_START(start_time);
126+
#endif
127+
122128
/* Perform the close operation */
123129

124130
ret = inode->u.i_ops->close(filep);
131+
132+
#ifdef CONFIG_FS_PROFILER
133+
VFS_PROFILE_STOP(start_time, g_vfs_profile.total_close_time,
134+
g_vfs_profile.closes);
135+
#endif
125136
}
126137

127138
/* And release the inode */

fs/vfs/fs_open.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "inode/inode.h"
4444
#include "driver/driver.h"
4545
#include "vfs.h"
46+
#include <nuttx/fs/fs_profile.h>
4647

4748
/****************************************************************************
4849
* Private Functions
@@ -236,6 +237,11 @@ static int file_vopen(FAR struct file *filep, FAR const char *path,
236237
* because it may also be closed that many times.
237238
*/
238239

240+
#ifdef CONFIG_FS_PROFILER
241+
struct timespec start_time;
242+
VFS_PROFILE_START(start_time);
243+
#endif
244+
239245
if (oflags & O_DIRECTORY)
240246
{
241247
ret = dir_allocate(filep, desc.relpath);
@@ -261,6 +267,11 @@ static int file_vopen(FAR struct file *filep, FAR const char *path,
261267
ret = -ENXIO;
262268
}
263269

270+
#ifdef CONFIG_FS_PROFILER
271+
VFS_PROFILE_STOP(start_time, g_vfs_profile.total_open_time,
272+
g_vfs_profile.opens);
273+
#endif
274+
264275
if (ret == -EISDIR && ((oflags & O_WRONLY) == 0))
265276
{
266277
ret = dir_allocate(filep, desc.relpath);

fs/vfs/fs_profile.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/****************************************************************************
2+
* fs/vfs/fs_profile.c
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Licensed to the Apache Software Foundation (ASF) under one or more
7+
* contributor license agreements. See the NOTICE file distributed with
8+
* this work for additional information regarding copyright ownership. The
9+
* ASF licenses this file to you under the Apache License, Version 2.0 (the
10+
* "License"); you may not use this file except in compliance with the
11+
* License. You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18+
* License for the specific language governing permissions and limitations
19+
* under the License.
20+
*
21+
****************************************************************************/
22+
23+
/****************************************************************************
24+
* Included Files
25+
****************************************************************************/
26+
27+
#include <nuttx/config.h>
28+
#include <nuttx/fs/fs_profile.h>
29+
#include <nuttx/clock.h>
30+
#include <nuttx/irq.h>
31+
32+
/****************************************************************************
33+
* Public Data
34+
****************************************************************************/
35+
36+
struct vfs_profile_s g_vfs_profile;
37+
38+
/****************************************************************************
39+
* Public Functions
40+
****************************************************************************/
41+
42+
void vfs_profile_start(FAR struct timespec *start)
43+
{
44+
clock_systime_timespec(start);
45+
}
46+
47+
void vfs_profile_stop(FAR struct timespec *start, FAR uint64_t *total,
48+
FAR uint32_t *count)
49+
{
50+
struct timespec stop;
51+
uint64_t nsec;
52+
irqstate_t flags;
53+
54+
clock_systime_timespec(&stop);
55+
56+
nsec = (stop.tv_sec - start->tv_sec) * 1000000000ULL +
57+
(stop.tv_nsec - start->tv_nsec);
58+
59+
/* Ensure thread-safe update using interrupts disable. */
60+
61+
flags = enter_critical_section();
62+
*total += nsec;
63+
*count += 1;
64+
leave_critical_section(flags);
65+
}

fs/vfs/fs_read.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include "inode/inode.h"
3939
#include "vfs.h"
40+
#include <nuttx/fs/fs_profile.h>
4041

4142
/****************************************************************************
4243
* Private Functions
@@ -206,6 +207,11 @@ ssize_t file_readv(FAR struct file *filep,
206207

207208
else if (inode != NULL && inode->u.i_ops)
208209
{
210+
#ifdef CONFIG_FS_PROFILER
211+
struct timespec start_time;
212+
VFS_PROFILE_START(start_time);
213+
#endif
214+
209215
if (inode->u.i_ops->readv)
210216
{
211217
struct uio uio;
@@ -220,6 +226,11 @@ ssize_t file_readv(FAR struct file *filep,
220226
{
221227
ret = file_readv_compat(filep, iov, iovcnt);
222228
}
229+
230+
#ifdef CONFIG_FS_PROFILER
231+
VFS_PROFILE_STOP(start_time, g_vfs_profile.total_read_time,
232+
g_vfs_profile.reads);
233+
#endif
223234
}
224235

225236
/* Return the number of bytes read (or possibly an error code) */

0 commit comments

Comments
 (0)