xref: /freebsd-src/sys/contrib/openzfs/module/zcommon/simd_stat.c (revision dd21556857e8d40f66bf5ad54754d9d52669ebf7)
17a7741afSMartin Matuska /*
27a7741afSMartin Matuska  * CDDL HEADER START
37a7741afSMartin Matuska  *
47a7741afSMartin Matuska  * The contents of this file are subject to the terms of the
57a7741afSMartin Matuska  * Common Development and Distribution License (the "License").
67a7741afSMartin Matuska  * You may not use this file except in compliance with the License.
77a7741afSMartin Matuska  *
87a7741afSMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97a7741afSMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
107a7741afSMartin Matuska  * See the License for the specific language governing permissions
117a7741afSMartin Matuska  * and limitations under the License.
127a7741afSMartin Matuska  *
137a7741afSMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
147a7741afSMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157a7741afSMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
167a7741afSMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
177a7741afSMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
187a7741afSMartin Matuska  *
197a7741afSMartin Matuska  * CDDL HEADER END
207a7741afSMartin Matuska  */
217a7741afSMartin Matuska /*
227a7741afSMartin Matuska  * Copyright 2024 Google, Inc.  All rights reserved.
237a7741afSMartin Matuska  */
247a7741afSMartin Matuska #include <sys/zfs_context.h>
257a7741afSMartin Matuska #include <sys/kstat.h>
267a7741afSMartin Matuska #include <sys/simd.h>
277a7741afSMartin Matuska 
287a7741afSMartin Matuska 
297a7741afSMartin Matuska #ifdef _KERNEL
307a7741afSMartin Matuska #ifdef __linux__
317a7741afSMartin Matuska #include <linux/simd.h>
327a7741afSMartin Matuska #endif /* __linux__ */
337a7741afSMartin Matuska kstat_t *simd_stat_kstat;
347a7741afSMartin Matuska #endif /* _KERNEL */
357a7741afSMartin Matuska 
367a7741afSMartin Matuska #ifdef _KERNEL
377a7741afSMartin Matuska /* Sometimes, we don't define these at all. */
387a7741afSMartin Matuska #ifndef HAVE_KERNEL_FPU
397a7741afSMartin Matuska #define	HAVE_KERNEL_FPU (0)
407a7741afSMartin Matuska #endif
417a7741afSMartin Matuska #ifndef HAVE_KERNEL_NEON
427a7741afSMartin Matuska #define	HAVE_KERNEL_NEON (0)
437a7741afSMartin Matuska #endif
447a7741afSMartin Matuska #ifndef HAVE_KERNEL_FPU_INTERNAL
457a7741afSMartin Matuska #define	HAVE_KERNEL_FPU_INTERNAL (0)
467a7741afSMartin Matuska #endif
477a7741afSMartin Matuska #ifndef HAVE_UNDERSCORE_KERNEL_FPU
487a7741afSMartin Matuska #define	HAVE_UNDERSCORE_KERNEL_FPU (0)
497a7741afSMartin Matuska #endif
507a7741afSMartin Matuska 
517a7741afSMartin Matuska #define	SIMD_STAT_PRINT(s, feat, val) \
527a7741afSMartin Matuska 	kmem_scnprintf(s + off, MAX(4095-off, 0), "%-16s\t%1d\n", feat, (val))
537a7741afSMartin Matuska 
547a7741afSMartin Matuska static int
557a7741afSMartin Matuska simd_stat_kstat_data(char *buf, size_t size, void *data)
567a7741afSMartin Matuska {
577a7741afSMartin Matuska 	(void) data;
587a7741afSMartin Matuska 
597a7741afSMartin Matuska 	static char simd_stat_kstat_payload[4096] = {0};
607a7741afSMartin Matuska 	static int off = 0;
617a7741afSMartin Matuska #ifdef __linux__
627a7741afSMartin Matuska 	if (off == 0) {
637a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
647a7741afSMartin Matuska 		    "kfpu_allowed", kfpu_allowed());
657a7741afSMartin Matuska #if defined(__x86_64__) || defined(__i386__)
667a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
677a7741afSMartin Matuska 		    "kfpu", HAVE_KERNEL_FPU);
687a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
697a7741afSMartin Matuska 		    "kfpu_internal", HAVE_KERNEL_FPU_INTERNAL);
707a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
717a7741afSMartin Matuska 		    "__kernel_fpu", HAVE_UNDERSCORE_KERNEL_FPU);
727a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
737a7741afSMartin Matuska 		    "sse", zfs_sse_available());
747a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
757a7741afSMartin Matuska 		    "sse2", zfs_sse2_available());
767a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
777a7741afSMartin Matuska 		    "sse3", zfs_sse3_available());
787a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
797a7741afSMartin Matuska 		    "ssse3", zfs_ssse3_available());
807a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
817a7741afSMartin Matuska 		    "sse41", zfs_sse4_1_available());
827a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
837a7741afSMartin Matuska 		    "sse42", zfs_sse4_2_available());
847a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
857a7741afSMartin Matuska 		    "avx", zfs_avx_available());
867a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
877a7741afSMartin Matuska 		    "avx2", zfs_avx2_available());
887a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
897a7741afSMartin Matuska 		    "avx512f", zfs_avx512f_available());
907a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
917a7741afSMartin Matuska 		    "avx512cd", zfs_avx512cd_available());
927a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
937a7741afSMartin Matuska 		    "avx512er", zfs_avx512er_available());
947a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
957a7741afSMartin Matuska 		    "avx512pf", zfs_avx512pf_available());
967a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
977a7741afSMartin Matuska 		    "avx512bw", zfs_avx512bw_available());
987a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
997a7741afSMartin Matuska 		    "avx512dq", zfs_avx512dq_available());
1007a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1017a7741afSMartin Matuska 		    "avx512vl", zfs_avx512vl_available());
1027a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1037a7741afSMartin Matuska 		    "avx512ifma", zfs_avx512ifma_available());
1047a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1057a7741afSMartin Matuska 		    "avx512vbmi", zfs_avx512vbmi_available());
1067a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1077a7741afSMartin Matuska 		    "ymm", __ymm_enabled());
1087a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1097a7741afSMartin Matuska 		    "zmm", __zmm_enabled());
1107a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1117a7741afSMartin Matuska 		    "bmi1", zfs_bmi1_available());
1127a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1137a7741afSMartin Matuska 		    "bmi2", zfs_bmi2_available());
1147a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1157a7741afSMartin Matuska 		    "aes", zfs_aes_available());
1167a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1177a7741afSMartin Matuska 		    "pclmulqdq", zfs_pclmulqdq_available());
1187a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1197a7741afSMartin Matuska 		    "movbe", zfs_movbe_available());
1207a7741afSMartin Matuska 
1217a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1227a7741afSMartin Matuska 		    "osxsave", boot_cpu_has(X86_FEATURE_OSXSAVE));
1237a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1247a7741afSMartin Matuska 		    "xsaves", static_cpu_has(X86_FEATURE_XSAVES));
1257a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1267a7741afSMartin Matuska 		    "xsaveopt", static_cpu_has(X86_FEATURE_XSAVEOPT));
1277a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1287a7741afSMartin Matuska 		    "xsave", static_cpu_has(X86_FEATURE_XSAVE));
1297a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1307a7741afSMartin Matuska 		    "fxsr", static_cpu_has(X86_FEATURE_FXSR));
1317a7741afSMartin Matuska #endif /* __x86__ */
1327a7741afSMartin Matuska #if defined(__arm__) || defined(__aarch64__)
1337a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1347a7741afSMartin Matuska 		    "kernel_neon", HAVE_KERNEL_NEON);
135*dd215568SMartin Matuska #if defined(CONFIG_KERNEL_MODE_NEON)
1367a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1377a7741afSMartin Matuska 		    "kernel_mode_neon", CONFIG_KERNEL_MODE_NEON);
138*dd215568SMartin Matuska #endif /* CONFIG_KERNEL_MODE_NEON */
1397a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1407a7741afSMartin Matuska 		    "neon", zfs_neon_available());
1417a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1427a7741afSMartin Matuska 		    "sha256", zfs_sha256_available());
1437a7741afSMartin Matuska #if defined(__aarch64__)
1447a7741afSMartin Matuska 		/*
1457a7741afSMartin Matuska 		 * This technically can exist on 32b ARM but we don't
1467a7741afSMartin Matuska 		 * define hooks to check for it and I didn't want to
1477a7741afSMartin Matuska 		 * learn enough ARM ASM to add one.
1487a7741afSMartin Matuska 		 */
1497a7741afSMartin Matuska 		off += SIMD_STAT_PRINT(simd_stat_kstat_payload,
1507a7741afSMartin Matuska 		    "sha512", zfs_sha512_available());
1517a7741afSMartin Matuska #endif /* __aarch64__ */
1527a7741afSMartin Matuska #endif /* __arm__ */
1537a7741afSMartin Matuska 		/* We want to short-circuit this on unsupported platforms. */
1547a7741afSMartin Matuska 		off += 1;
1557a7741afSMartin Matuska 	}
1567a7741afSMartin Matuska 
1577a7741afSMartin Matuska 	kmem_scnprintf(buf, MIN(off, size), "%s", simd_stat_kstat_payload);
1587a7741afSMartin Matuska #endif /* __linux__ */
1597a7741afSMartin Matuska 	return (0);
1607a7741afSMartin Matuska }
1617a7741afSMartin Matuska #endif /* _KERNEL */
1627a7741afSMartin Matuska 
1637a7741afSMartin Matuska void
1647a7741afSMartin Matuska simd_stat_init(void)
1657a7741afSMartin Matuska {
1667a7741afSMartin Matuska 	static boolean_t simd_stat_initialized = B_FALSE;
1677a7741afSMartin Matuska 
1687a7741afSMartin Matuska 	if (!simd_stat_initialized) {
1697a7741afSMartin Matuska #if defined(_KERNEL)
1707a7741afSMartin Matuska 		/* Install kstats for all implementations */
1717a7741afSMartin Matuska 		simd_stat_kstat = kstat_create("zfs", 0, "simd", "misc",
1727a7741afSMartin Matuska 		    KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
1737a7741afSMartin Matuska 
1747a7741afSMartin Matuska 
1757a7741afSMartin Matuska 		if (simd_stat_kstat != NULL) {
1767a7741afSMartin Matuska 			simd_stat_kstat->ks_data = (void*)(uintptr_t)1;
1777a7741afSMartin Matuska 			simd_stat_kstat->ks_ndata = 1;
1787a7741afSMartin Matuska 			simd_stat_kstat->ks_flags |= KSTAT_FLAG_NO_HEADERS;
1797a7741afSMartin Matuska 			kstat_set_raw_ops(simd_stat_kstat,
1807a7741afSMartin Matuska 			    NULL,
1817a7741afSMartin Matuska 			    simd_stat_kstat_data,
1827a7741afSMartin Matuska 			    NULL);
1837a7741afSMartin Matuska 			kstat_install(simd_stat_kstat);
1847a7741afSMartin Matuska 		}
1857a7741afSMartin Matuska #endif /* _KERNEL */
1867a7741afSMartin Matuska 	}
1877a7741afSMartin Matuska 	/* Finish initialization */
1887a7741afSMartin Matuska 	simd_stat_initialized = B_TRUE;
1897a7741afSMartin Matuska }
1907a7741afSMartin Matuska 
1917a7741afSMartin Matuska void
1927a7741afSMartin Matuska simd_stat_fini(void)
1937a7741afSMartin Matuska {
1947a7741afSMartin Matuska #if defined(_KERNEL)
1957a7741afSMartin Matuska 	if (simd_stat_kstat != NULL) {
1967a7741afSMartin Matuska 		kstat_delete(simd_stat_kstat);
1977a7741afSMartin Matuska 		simd_stat_kstat = NULL;
1987a7741afSMartin Matuska 	}
1997a7741afSMartin Matuska #endif
2007a7741afSMartin Matuska }
2017a7741afSMartin Matuska 
2027a7741afSMartin Matuska #ifdef _KERNEL
2037a7741afSMartin Matuska EXPORT_SYMBOL(simd_stat_init);
2047a7741afSMartin Matuska EXPORT_SYMBOL(simd_stat_fini);
2057a7741afSMartin Matuska #endif
206