Skip to content

Commit 5d01243

Browse files
authored
Add SIMD metadata in /proc on Linux
Too many times, people's performance problems have amounted to "somehow your SIMD support isn't working", and determining that at runtime is difficult to describe to people. This adds a /proc/spl/kstat/zfs/simd node, which exposes metadata about which instructions ZFS thinks it can use, on AArch64 and x86_64 Linux, to make investigating things like this much easier. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Rich Ercolani <[email protected]> Closes #16530
1 parent 45a4a94 commit 5d01243

File tree

7 files changed

+207
-0
lines changed

7 files changed

+207
-0
lines changed

include/os/freebsd/spl/sys/simd.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,7 @@
5050
#define kfpu_fini() do {} while (0)
5151
#endif
5252

53+
#define simd_stat_init() 0
54+
#define simd_stat_fini() 0
55+
5356
#endif

include/os/linux/kernel/linux/simd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,8 @@
4545
#define kfpu_fini() ((void) 0)
4646

4747
#endif
48+
49+
void simd_stat_init(void);
50+
void simd_stat_fini(void);
51+
4852
#endif /* _LINUX_SIMD_H */

lib/libspl/include/sys/simd.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,4 +592,7 @@ zfs_isa207_available(void)
592592

593593
#endif
594594

595+
extern void simd_stat_init(void);
596+
extern void simd_stat_fini(void);
597+
595598
#endif /* _LIBSPL_SYS_SIMD_H */

lib/libzpool/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ nodist_libzpool_la_SOURCES = \
5050
module/os/linux/zfs/zio_crypt.c \
5151
\
5252
module/zcommon/cityhash.c \
53+
module/zcommon/simd_stat.c \
5354
module/zcommon/zfeature_common.c \
5455
module/zcommon/zfs_comutil.c \
5556
module/zcommon/zfs_deleg.c \

module/Kbuild.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ zfs-objs += $(addprefix unicode/,$(UNICODE_OBJS))
232232

233233
ZCOMMON_OBJS := \
234234
cityhash.o \
235+
simd_stat.o \
235236
zfeature_common.o \
236237
zfs_comutil.o \
237238
zfs_deleg.o \

module/zcommon/simd_stat.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9+
* or https://opensource.org/licenses/CDDL-1.0.
10+
* See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*
13+
* When distributing Covered Code, include this CDDL HEADER in each
14+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15+
* If applicable, add the following below this CDDL HEADER, with the
16+
* fields enclosed by brackets "[]" replaced with your own identifying
17+
* information: Portions Copyright [yyyy] [name of copyright owner]
18+
*
19+
* CDDL HEADER END
20+
*/
21+
/*
22+
* Copyright 2024 Google, Inc. All rights reserved.
23+
*/
24+
#include <sys/zfs_context.h>
25+
#include <sys/kstat.h>
26+
#include <sys/simd.h>
27+
28+
29+
#ifdef _KERNEL
30+
#ifdef __linux__
31+
#include <linux/simd.h>
32+
#endif /* __linux__ */
33+
kstat_t *simd_stat_kstat;
34+
#endif /* _KERNEL */
35+
36+
#ifdef _KERNEL
37+
#define SIMD_STAT_PRINT(s, feat, val) \
38+
kmem_scnprintf(s + off, MAX(4095-off, 0), "%-16s\t%1d\n", feat, (val))
39+
40+
static int
41+
simd_stat_kstat_data(char *buf, size_t size, void *data)
42+
{
43+
(void) data;
44+
45+
static char simd_stat_kstat_payload[4096] = {0};
46+
static int off = 0;
47+
#ifdef __linux__
48+
if (off == 0) {
49+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
50+
"kfpu_allowed", kfpu_allowed());
51+
#ifdef __x86__
52+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
53+
"kfpu", HAVE_KERNEL_FPU);
54+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
55+
"kfpu_internal", HAVE_KERNEL_FPU_INTERNAL);
56+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
57+
"__kernel_fpu", HAVE_UNDERSCORE_KERNEL_FPU);
58+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
59+
"sse", zfs_sse_available());
60+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
61+
"sse2", zfs_sse2_available());
62+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
63+
"sse3", zfs_sse3_available());
64+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
65+
"ssse3", zfs_ssse3_available());
66+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
67+
"sse41", zfs_sse4_1_available());
68+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
69+
"sse42", zfs_sse4_2_available());
70+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
71+
"avx", zfs_avx_available());
72+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
73+
"avx2", zfs_avx2_available());
74+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
75+
"avx512f", zfs_avx512f_available());
76+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
77+
"avx512cd", zfs_avx512cd_available());
78+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
79+
"avx512er", zfs_avx512er_available());
80+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
81+
"avx512pf", zfs_avx512pf_available());
82+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
83+
"avx512bw", zfs_avx512bw_available());
84+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
85+
"avx512dq", zfs_avx512dq_available());
86+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
87+
"avx512vl", zfs_avx512vl_available());
88+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
89+
"avx512ifma", zfs_avx512ifma_available());
90+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
91+
"avx512vbmi", zfs_avx512vbmi_available());
92+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
93+
"ymm", __ymm_enabled());
94+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
95+
"zmm", __zmm_enabled());
96+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
97+
"bmi1", zfs_bmi1_available());
98+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
99+
"bmi2", zfs_bmi2_available());
100+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
101+
"aes", zfs_aes_available());
102+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
103+
"pclmulqdq", zfs_pclmulqdq_available());
104+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
105+
"movbe", zfs_movbe_available());
106+
107+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
108+
"osxsave", boot_cpu_has(X86_FEATURE_OSXSAVE));
109+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
110+
"xsaves", static_cpu_has(X86_FEATURE_XSAVES));
111+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
112+
"xsaveopt", static_cpu_has(X86_FEATURE_XSAVEOPT));
113+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
114+
"xsave", static_cpu_has(X86_FEATURE_XSAVE));
115+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
116+
"fxsr", static_cpu_has(X86_FEATURE_FXSR));
117+
#endif /* __x86__ */
118+
#if defined(__arm__) || defined(__aarch64__)
119+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
120+
"kernel_neon", HAVE_KERNEL_NEON);
121+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
122+
"kernel_mode_neon", CONFIG_KERNEL_MODE_NEON);
123+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
124+
"neon", zfs_neon_available());
125+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
126+
"sha256", zfs_sha256_available());
127+
#if defined(__aarch64__)
128+
/*
129+
* This technically can exist on 32b ARM but we don't
130+
* define hooks to check for it and I didn't want to
131+
* learn enough ARM ASM to add one.
132+
*/
133+
off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
134+
"sha512", zfs_sha512_available());
135+
#endif /* __aarch64__ */
136+
#endif /* __arm__ */
137+
/* We want to short-circuit this on unsupported platforms. */
138+
off += 1;
139+
}
140+
141+
kmem_scnprintf(buf, MIN(off, size), "%s", simd_stat_kstat_payload);
142+
#endif /* __linux__ */
143+
return (0);
144+
}
145+
#endif /* _KERNEL */
146+
147+
void
148+
simd_stat_init(void)
149+
{
150+
static boolean_t simd_stat_initialized = B_FALSE;
151+
152+
if (!simd_stat_initialized) {
153+
#if defined(_KERNEL)
154+
/* Install kstats for all implementations */
155+
simd_stat_kstat = kstat_create("zfs", 0, "simd", "misc",
156+
KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
157+
158+
159+
if (simd_stat_kstat != NULL) {
160+
simd_stat_kstat->ks_data = (void*)(uintptr_t)1;
161+
simd_stat_kstat->ks_ndata = 1;
162+
simd_stat_kstat->ks_flags |= KSTAT_FLAG_NO_HEADERS;
163+
kstat_set_raw_ops(simd_stat_kstat,
164+
NULL,
165+
simd_stat_kstat_data,
166+
NULL);
167+
kstat_install(simd_stat_kstat);
168+
}
169+
#endif /* _KERNEL */
170+
}
171+
/* Finish initialization */
172+
simd_stat_initialized = B_TRUE;
173+
}
174+
175+
void
176+
simd_stat_fini(void)
177+
{
178+
#if defined(_KERNEL)
179+
if (simd_stat_kstat != NULL) {
180+
kstat_delete(simd_stat_kstat);
181+
simd_stat_kstat = NULL;
182+
}
183+
#endif
184+
}
185+
186+
#ifdef _KERNEL
187+
EXPORT_SYMBOL(simd_stat_init);
188+
EXPORT_SYMBOL(simd_stat_fini);
189+
#endif

module/zcommon/zfs_prop.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <sys/zfs_ioctl.h>
4242
#include <sys/zfs_znode.h>
4343
#include <sys/dsl_crypt.h>
44+
#include <sys/simd.h>
4445

4546
#include "zfs_prop.h"
4647
#include "zfs_deleg.h"
@@ -1074,6 +1075,9 @@ EXPORT_SYMBOL(zfs_kfpu_fpregs);
10741075
extern int __init zcommon_init(void);
10751076
extern void zcommon_fini(void);
10761077

1078+
extern void simd_stat_init(void);
1079+
extern void simd_stat_fini(void);
1080+
10771081
int __init
10781082
zcommon_init(void)
10791083
{
@@ -1082,13 +1086,15 @@ zcommon_init(void)
10821086
return (error);
10831087

10841088
fletcher_4_init();
1089+
simd_stat_init();
10851090

10861091
return (0);
10871092
}
10881093

10891094
void
10901095
zcommon_fini(void)
10911096
{
1097+
simd_stat_fini();
10921098
fletcher_4_fini();
10931099
kfpu_fini();
10941100
}

0 commit comments

Comments
 (0)