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