1 /*
2 * Copyright (C) 2013-2021 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * This code is a complete clean re-write of the stress tool by
19 * Colin Ian King <colin.king@canonical.com> and attempts to be
20 * backwardly compatible with the stress tool by Amos Waterland
21 * <apw@rossby.metr.ou.edu> but has more stress tests and more
22 * functionality.
23 *
24 */
25 #include "stress-ng.h"
26
27 static const stress_help_t help[] = {
28 { NULL, "nop N", "start N workers that burn cycles with no-ops" },
29 { NULL, "nop-ops N", "stop after N nop bogo no-op operations" },
30 { NULL, "nop-instr INSTR", "specify nop instruction to use" },
31 { NULL, NULL, NULL }
32 };
33
34 #if defined(HAVE_ASM_NOP)
35
36 static sigjmp_buf jmpbuf;
37
38 typedef struct {
39 const char *name;
40 void (*func)(const stress_args_t *args);
41 } stress_nop_instr_t;
42
43 #define OPx1(op) op();
44 #define OPx4(op) OPx1(op) OPx1(op) OPx1(op) OPx1(op)
45 #define OPx16(op) OPx4(op) OPx4(op) OPx4(op) OPx4(op)
46 #define OPx64(op) do { OPx16(op) OPx16(op) OPx16(op) OPx16(op) } while (0)
47
48 #define STRESS_NOP_SPIN_OP(name, op) \
49 static void stress_nop_spin_ ## name(const stress_args_t *args) \
50 { \
51 do { \
52 register int i = 1024; \
53 \
54 while (i--) \
55 OPx64(op); \
56 \
57 inc_counter(args); \
58 } while (keep_stressing(args)); \
59 }
60
stress_op_nop(void)61 static inline void stress_op_nop(void)
62 {
63 #if defined(STRESS_ARCH_KVX)
64 /*
65 * Extra ;; required for KVX to indicate end of
66 * a VLIW instruction bundle
67 */
68 __asm__ __volatile__("nop;;\n");
69 #else
70 __asm__ __volatile__("nop;\n");
71 #endif
72 }
73
STRESS_NOP_SPIN_OP(nop,stress_op_nop)74 STRESS_NOP_SPIN_OP(nop, stress_op_nop)
75
76 #if defined(HAVE_ASM_X86_PAUSE)
77 static inline void stress_op_x86_pause(void)
78 {
79 __asm__ __volatile__("pause;\n" ::: "memory");
80 }
81
82 STRESS_NOP_SPIN_OP(x86_pause, stress_op_x86_pause);
83 #endif
84
85 #if defined(HAVE_ASM_ARM_YIELD)
stress_op_arm_yield(void)86 static inline void stress_op_arm_yield(void)
87 {
88 __asm__ __volatile__("yield;\n");
89 }
90
91 STRESS_NOP_SPIN_OP(arm_yield, stress_op_arm_yield);
92 #endif
93
94 #if defined(STRESS_ARCH_X86)
stress_op_x86_nop2(void)95 static inline void stress_op_x86_nop2(void)
96 {
97 __asm__ __volatile__(".byte 0x66, 0x90;\n");
98 }
99
stress_op_x86_nop3(void)100 static inline void stress_op_x86_nop3(void)
101 {
102 __asm__ __volatile__(".byte 0x0f, 0x1f, 0x00;\n");
103 }
104
stress_op_x86_nop4(void)105 static inline void stress_op_x86_nop4(void)
106 {
107 __asm__ __volatile__(".byte 0x0f, 0x1f, 0x40, 0x00;\n");
108 }
109
stress_op_x86_nop5(void)110 static inline void stress_op_x86_nop5(void)
111 {
112 __asm__ __volatile__(".byte 0x0f, 0x1f, 0x44, 0x00, 0x00;\n");
113 }
114
stress_op_x86_nop6(void)115 static inline void stress_op_x86_nop6(void)
116 {
117 __asm__ __volatile__(".byte 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00;\n");
118 }
119
stress_op_x86_nop7(void)120 static inline void stress_op_x86_nop7(void)
121 {
122 __asm__ __volatile__(".byte 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00;\n");
123 }
124
stress_op_x86_nop8(void)125 static inline void stress_op_x86_nop8(void)
126 {
127 __asm__ __volatile__(".byte 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00;\n");
128 }
129
stress_op_x86_nop9(void)130 static inline void stress_op_x86_nop9(void)
131 {
132 __asm__ __volatile__(".byte 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00;\n");
133 }
134
stress_op_x86_nop10(void)135 static inline void stress_op_x86_nop10(void)
136 {
137 __asm__ __volatile__(".byte 0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00;\n");
138 }
139
stress_op_x86_nop11(void)140 static inline void stress_op_x86_nop11(void)
141 {
142 __asm__ __volatile__(".byte 0x66, 0x66, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00;\n");
143 }
144
145 STRESS_NOP_SPIN_OP(x86_nop2, stress_op_x86_nop2);
146 STRESS_NOP_SPIN_OP(x86_nop3, stress_op_x86_nop3);
147 STRESS_NOP_SPIN_OP(x86_nop4, stress_op_x86_nop4);
148 STRESS_NOP_SPIN_OP(x86_nop5, stress_op_x86_nop5);
149 STRESS_NOP_SPIN_OP(x86_nop6, stress_op_x86_nop6);
150 STRESS_NOP_SPIN_OP(x86_nop7, stress_op_x86_nop7);
151 STRESS_NOP_SPIN_OP(x86_nop8, stress_op_x86_nop8);
152 STRESS_NOP_SPIN_OP(x86_nop9, stress_op_x86_nop9);
153 STRESS_NOP_SPIN_OP(x86_nop10, stress_op_x86_nop10);
154 STRESS_NOP_SPIN_OP(x86_nop11, stress_op_x86_nop11);
155 #endif
156
157 stress_nop_instr_t nop_instr[] = {
158 { "nop", stress_nop_spin_nop },
159 #if defined(STRESS_ARCH_X86)
160 { "nop2", stress_nop_spin_x86_nop2 },
161 { "nop3", stress_nop_spin_x86_nop3 },
162 { "nop4", stress_nop_spin_x86_nop4 },
163 { "nop5", stress_nop_spin_x86_nop5 },
164 { "nop6", stress_nop_spin_x86_nop6 },
165 { "nop7", stress_nop_spin_x86_nop7 },
166 { "nop8", stress_nop_spin_x86_nop8 },
167 { "nop9", stress_nop_spin_x86_nop9 },
168 { "nop10", stress_nop_spin_x86_nop10 },
169 { "nop11", stress_nop_spin_x86_nop11 },
170 #endif
171 #if defined(HAVE_ASM_X86_PAUSE)
172 { "pause", stress_nop_spin_x86_pause },
173 #endif
174 #if defined(HAVE_ASM_ARM_YIELD)
175 { "yield", stress_nop_spin_arm_yield },
176 #endif
177 { NULL, NULL },
178 };
179
stress_set_nop_instr(const char * opt)180 static int stress_set_nop_instr(const char *opt)
181 {
182 stress_nop_instr_t const *instr;
183
184 for (instr = nop_instr; instr->func; instr++) {
185 if (!strcmp(instr->name, opt)) {
186 stress_set_setting("nop-instr", TYPE_ID_UINTPTR_T, &instr);
187 return 0;
188 }
189 }
190
191 (void)fprintf(stderr, "nop-instr must be one of:");
192 for (instr = nop_instr; instr->func; instr++) {
193 (void)fprintf(stderr, " %s", instr->name);
194 }
195 (void)fprintf(stderr, "\n");
196
197 return -1;
198 }
199
stress_sigill_nop_handler(int signum)200 static void stress_sigill_nop_handler(int signum)
201 {
202 (void)signum;
203
204 siglongjmp(jmpbuf, 1);
205 }
206
207 /*
208 * stress_nop()
209 * stress that does lots of not a lot
210 */
stress_nop(const stress_args_t * args)211 static int stress_nop(const stress_args_t *args)
212 {
213 stress_nop_instr_t const *instr = &nop_instr[0];
214
215 (void)stress_get_setting("nop-instr", &instr);
216
217 if (stress_sighandler(args->name, SIGILL, stress_sigill_nop_handler, NULL) < 0)
218 return EXIT_NO_RESOURCE;
219
220 if (sigsetjmp(jmpbuf, 1) != 0) {
221 /* We reach here on an SIGILL trap */
222 if (instr != &nop_instr[0]) {
223 pr_inf("%s '%s' instruction was illegal, falling back to nop\n",
224 args->name, instr->name);
225 instr = &nop_instr[0];
226 } else {
227 /* Really should be able to do nop, skip */
228 pr_inf("%s 'nop' instruction was illegal, skipping stressor\n",
229 args->name);
230 return EXIT_NO_RESOURCE;
231 }
232 }
233
234 stress_set_proc_state(args->name, STRESS_STATE_RUN);
235 instr->func(args);
236 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
237
238 return EXIT_SUCCESS;
239 }
240
241 static const stress_opt_set_func_t opt_set_funcs[] = {
242 { OPT_nop_instr, stress_set_nop_instr },
243 { 0, NULL }
244 };
245
246 stressor_info_t stress_nop_info = {
247 .stressor = stress_nop,
248 .class = CLASS_CPU,
249 .opt_set_funcs = opt_set_funcs,
250 .help = help
251 };
252 #else
253 stressor_info_t stress_nop_info = {
254 .stressor = stress_not_implemented,
255 .class = CLASS_CPU,
256 .help = help
257 };
258 #endif
259