1 /*
2 * Copyright (C) 2013-2021 Canonical, Ltd.
3 * Copyright (C) 2021 Colin Ian King.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20 #include "stress-ng.h"
21
22 static const stress_help_t help[] = {
23 { NULL, "tsc N", "start N workers reading the time stamp counter" },
24 { NULL, "tsc-ops N", "stop after N TSC bogo operations" },
25 { NULL, NULL, NULL }
26 };
27
28
29 #if defined(STRESS_ARCH_RISCV) && \
30 defined(SIGILL)
31
32 #define HAVE_STRESS_TSC_CAPABILITY
33
34 static sigjmp_buf jmpbuf;
35 static bool tsc_supported = false;
36
rdtsc(void)37 static inline unsigned long rdtsc(void)
38 {
39 register unsigned long ticks;
40
41 __asm__ __volatile__("rdtime %0"
42 : "=r" (ticks)
43 :
44 : "memory");
45 return ticks;
46 }
47
stress_sigill_handler(int signum)48 static void stress_sigill_handler(int signum)
49 {
50 (void)signum;
51
52 siglongjmp(jmpbuf, 1);
53 }
54
55 /*
56 * stress_tsc_supported()
57 * check if tsc is supported, riscv variant
58 */
stress_tsc_supported(const char * name)59 static int stress_tsc_supported(const char *name)
60 {
61 unsigned long cycles;
62
63 if (stress_sighandler(name, SIGILL, stress_sigill_handler, NULL) < 0)
64 return -1;
65
66 /*
67 * We get here with non-zero return if SIGILL occurs
68 */
69 if (sigsetjmp(jmpbuf, 1) != 0) {
70 pr_inf_skip("%s stressor will be skipped, "
71 "rdcycle not allowed\n", name);
72 return -1;
73 }
74
75 cycles = rdtsc();
76 (void)cycles;
77 tsc_supported = true;
78
79 return 0;
80 }
81 #endif
82
83 #if defined(STRESS_ARCH_X86)
84
85 #define HAVE_STRESS_TSC_CAPABILITY
86
87 static bool tsc_supported = false;
88
89 /*
90 * stress_tsc_supported()
91 * check if tsc is supported, x86 variant
92 */
stress_tsc_supported(const char * name)93 static int stress_tsc_supported(const char *name)
94 {
95 /* Intel CPU? */
96 if (!stress_cpu_is_x86()) {
97 pr_inf_skip("%s stressor will be skipped, "
98 "not a recognised Intel CPU\n", name);
99 return -1;
100 }
101 /* ..and supports tsc? */
102 if (!stress_cpu_x86_has_tsc()) {
103 pr_inf_skip("%s stressor will be skipped, CPU "
104 "does not support the tsc instruction\n", name);
105 return -1;
106 }
107 tsc_supported = true;
108 return 0;
109 }
110
111 /*
112 * read tsc
113 */
rdtsc(void)114 static inline void rdtsc(void)
115 {
116 #if STRESS_TSC_SERIALIZED
117 asm volatile("cpuid\nrdtsc\n" : : : "%edx", "%eax");
118 #else
119 asm volatile("rdtsc\n" : : : "%edx", "%eax");
120 #endif
121 }
122
123 #elif defined(STRESS_ARCH_PPC64) && \
124 defined(HAVE_SYS_PLATFORM_PPC_H) && \
125 defined(HAVE_PPC_GET_TIMEBASE)
126
127 #define HAVE_STRESS_TSC_CAPABILITY
128
129 static bool tsc_supported = true;
130
131 /*
132 * stress_tsc_supported()
133 * check if tsc is supported, ppc variant
134 */
stress_tsc_supported(const char * name)135 static int stress_tsc_supported(const char *name)
136 {
137 (void)name;
138
139 return 0;
140 }
141
rdtsc(void)142 static inline void rdtsc(void)
143 {
144 (void)__ppc_get_timebase();
145 }
146
147 #elif defined(STRESS_ARCH_S390)
148
149 #define HAVE_STRESS_TSC_CAPABILITY
150
151 static bool tsc_supported = true;
152
153 /*
154 * stress_tsc_supported()
155 * check if tsc is supported, s390x variant
156 */
stress_tsc_supported(const char * name)157 static int stress_tsc_supported(const char *name)
158 {
159 (void)name;
160
161 return 0;
162 }
163
rdtsc(void)164 static inline void rdtsc(void)
165 {
166 uint64_t tick;
167
168 asm("\tstck\t%0\n" : "=Q" (tick) : : "cc");
169 }
170 #endif
171
172 #if defined(HAVE_STRESS_TSC_CAPABILITY)
173 /*
174 * Unrolled 32 times
175 */
176 #define TSCx32() \
177 { \
178 rdtsc(); \
179 rdtsc(); \
180 rdtsc(); \
181 rdtsc(); \
182 rdtsc(); \
183 rdtsc(); \
184 rdtsc(); \
185 rdtsc(); \
186 rdtsc(); \
187 rdtsc(); \
188 rdtsc(); \
189 rdtsc(); \
190 rdtsc(); \
191 rdtsc(); \
192 rdtsc(); \
193 rdtsc(); \
194 rdtsc(); \
195 rdtsc(); \
196 rdtsc(); \
197 rdtsc(); \
198 rdtsc(); \
199 rdtsc(); \
200 rdtsc(); \
201 rdtsc(); \
202 rdtsc(); \
203 rdtsc(); \
204 rdtsc(); \
205 rdtsc(); \
206 rdtsc(); \
207 rdtsc(); \
208 rdtsc(); \
209 rdtsc(); \
210 }
211
212 /*
213 * stress_tsc()
214 * stress Intel tsc instruction
215 */
stress_tsc(const stress_args_t * args)216 static int stress_tsc(const stress_args_t *args)
217 {
218 stress_set_proc_state(args->name, STRESS_STATE_RUN);
219
220 if (tsc_supported) {
221 do {
222 TSCx32();
223 TSCx32();
224 TSCx32();
225 TSCx32();
226 inc_counter(args);
227 } while (keep_stressing(args));
228 }
229 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
230
231 return EXIT_SUCCESS;
232 }
233
234 stressor_info_t stress_tsc_info = {
235 .stressor = stress_tsc,
236 .supported = stress_tsc_supported,
237 .class = CLASS_CPU,
238 .help = help
239 };
240 #else
241
stress_tsc_supported(const char * name)242 static int stress_tsc_supported(const char *name)
243 {
244 pr_inf_skip("%s stressor will be skipped, CPU "
245 "does not support the rdtsc instruction.\n", name);
246 return -1;
247 }
248
249 stressor_info_t stress_tsc_info = {
250 .stressor = stress_not_implemented,
251 .supported = stress_tsc_supported,
252 .class = CLASS_CPU,
253 .help = help
254 };
255 #endif
256