1 | /* Tests for x86 GLIBC_TUNABLES=glibc.cpu.hwcaps filter. |
2 | Copyright (C) 2023-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <array_length.h> |
20 | #include <getopt.h> |
21 | #include <ifunc-impl-list.h> |
22 | #include <spawn.h> |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | #include <intprops.h> |
27 | #include <support/check.h> |
28 | #include <support/support.h> |
29 | #include <support/xunistd.h> |
30 | #include <support/capture_subprocess.h> |
31 | |
32 | /* Nonzero if the program gets called via `exec'. */ |
33 | #define CMDLINE_OPTIONS \ |
34 | { "restart", no_argument, &restart, 1 }, |
35 | static int restart; |
36 | |
37 | /* Disable everything. */ |
38 | static const char *test_1[] = |
39 | { |
40 | "__memcpy_avx512_no_vzeroupper" , |
41 | "__memcpy_avx512_unaligned" , |
42 | "__memcpy_avx512_unaligned_erms" , |
43 | "__memcpy_evex_unaligned" , |
44 | "__memcpy_evex_unaligned_erms" , |
45 | "__memcpy_avx_unaligned" , |
46 | "__memcpy_avx_unaligned_erms" , |
47 | "__memcpy_avx_unaligned_rtm" , |
48 | "__memcpy_avx_unaligned_erms_rtm" , |
49 | "__memcpy_ssse3" , |
50 | }; |
51 | |
52 | static const struct test_t |
53 | { |
54 | const char *env; |
55 | const char *const *funcs; |
56 | size_t nfuncs; |
57 | } tests[] = |
58 | { |
59 | { |
60 | /* Disable everything. */ |
61 | "-Prefer_ERMS,-Prefer_FSRM,-AVX,-AVX2,-AVX512F,-AVX512VL," |
62 | "-SSE4_1,-SSE4_2,-SSSE3,-Fast_Unaligned_Load,-ERMS," |
63 | "-AVX_Fast_Unaligned_Load,-Avoid_Non_Temporal_Memset" , |
64 | test_1, |
65 | array_length (test_1) |
66 | }, |
67 | { |
68 | /* Same as before, but with some empty suboptions. */ |
69 | ",-,-Prefer_ERMS,-Prefer_FSRM,-AVX,-AVX2,-AVX512F,-AVX512VL," |
70 | "-SSE4_1,-SSE4_2,-SSSE3,-Fast_Unaligned_Load,,-," |
71 | "-ERMS,-AVX_Fast_Unaligned_Load,-Avoid_Non_Temporal_Memset,-," , |
72 | test_1, |
73 | array_length (test_1) |
74 | } |
75 | }; |
76 | |
77 | /* Called on process re-execution. */ |
78 | _Noreturn static void |
79 | handle_restart (int ntest) |
80 | { |
81 | struct libc_ifunc_impl impls[32]; |
82 | int cnt = __libc_ifunc_impl_list (name: "memcpy" , array: impls, array_length (impls)); |
83 | if (cnt == 0) |
84 | _exit (EXIT_SUCCESS); |
85 | TEST_VERIFY_EXIT (cnt >= 1); |
86 | for (int i = 0; i < cnt; i++) |
87 | { |
88 | for (int f = 0; f < tests[ntest].nfuncs; f++) |
89 | { |
90 | if (strcmp (impls[i].name, tests[ntest].funcs[f]) == 0) |
91 | TEST_COMPARE (impls[i].usable, false); |
92 | } |
93 | } |
94 | |
95 | _exit (EXIT_SUCCESS); |
96 | } |
97 | |
98 | static int |
99 | do_test (int argc, char *argv[]) |
100 | { |
101 | /* We must have either: |
102 | - One our fource parameters left if called initially: |
103 | + path to ld.so optional |
104 | + "--library-path" optional |
105 | + the library path optional |
106 | + the application name |
107 | + the test to check */ |
108 | |
109 | TEST_VERIFY_EXIT (argc == 2 || argc == 5); |
110 | |
111 | if (restart) |
112 | handle_restart (atoi (argv[1])); |
113 | |
114 | char nteststr[INT_BUFSIZE_BOUND (int)]; |
115 | |
116 | char *spargv[10]; |
117 | { |
118 | int i = 0; |
119 | for (; i < argc - 1; i++) |
120 | spargv[i] = argv[i + 1]; |
121 | spargv[i++] = (char *) "--direct" ; |
122 | spargv[i++] = (char *) "--restart" ; |
123 | spargv[i++] = nteststr; |
124 | spargv[i] = NULL; |
125 | } |
126 | |
127 | for (int i = 0; i < array_length (tests); i++) |
128 | { |
129 | snprintf (s: nteststr, maxlen: sizeof nteststr, format: "%d" , i); |
130 | |
131 | printf (format: "[%d] Spawned test for %s\n" , i, tests[i].env); |
132 | char *tunable = xasprintf (format: "glibc.cpu.hwcaps=%s" , tests[i].env); |
133 | setenv (name: "GLIBC_TUNABLES" , value: tunable, replace: 1); |
134 | |
135 | struct support_capture_subprocess result |
136 | = support_capture_subprogram (file: spargv[0], argv: spargv); |
137 | support_capture_subprocess_check (&result, context: "tst-tunables" , status_or_signal: 0, |
138 | allowed: sc_allow_stderr); |
139 | support_capture_subprocess_free (&result); |
140 | |
141 | free (ptr: tunable); |
142 | } |
143 | |
144 | return 0; |
145 | } |
146 | |
147 | #define TEST_FUNCTION_ARGV do_test |
148 | #include <support/test-driver.c> |
149 | |