1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include <getopt.h>
22#include <sys/reboot.h>
23#include <sys/syscall.h>
24#include <linux/random.h>
25#include <pthread.h>
26#include <sys/mount.h>
27
28const char *argv0;
29
30#define PAGE_SIZE 4096
31
32static int gettid(void)
33{
34 return syscall(SYS_gettid);
35}
36
37static __attribute__((noreturn)) void exit_failure(void)
38{
39 if (getpid() == 1) {
40 sync();
41 reboot(RB_POWER_OFF);
42 fprintf(stderr, "%s (%05d): ERROR: cannot reboot: %s\n",
43 argv0, gettid(), strerror(errno));
44 abort();
45 } else {
46 exit(1);
47 }
48}
49
50static __attribute__((noreturn)) void exit_success(void)
51{
52 if (getpid() == 1) {
53 sync();
54 reboot(RB_POWER_OFF);
55 fprintf(stderr, "%s (%05d): ERROR: cannot reboot: %s\n",
56 argv0, gettid(), strerror(errno));
57 abort();
58 } else {
59 exit(0);
60 }
61}
62
63static int get_command_arg_str(const char *name,
64 char **val)
65{
66 static char line[1024];
67 FILE *fp = fopen("/proc/cmdline", "r");
68 char *start, *end;
69
70 if (fp == NULL) {
71 fprintf(stderr, "%s (%05d): ERROR: cannot open /proc/cmdline: %s\n",
72 argv0, gettid(), strerror(errno));
73 return -1;
74 }
75
76 if (!fgets(line, sizeof line, fp)) {
77 fprintf(stderr, "%s (%05d): ERROR: cannot read /proc/cmdline: %s\n",
78 argv0, gettid(), strerror(errno));
79 fclose(fp);
80 return -1;
81 }
82 fclose(fp);
83
84 start = strstr(line, name);
85 if (!start)
86 return 0;
87
88 start += strlen(name);
89
90 if (*start != '=') {
91 fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
92 argv0, gettid(), name);
93 }
94 start++;
95
96 end = strstr(start, " ");
97 if (!end)
98 end = strstr(start, "\n");
99
100 if (end == start) {
101 fprintf(stderr, "%s (%05d): ERROR: no value provided for '%s' in /proc/cmdline\n",
102 argv0, gettid(), name);
103 return -1;
104 }
105
106 if (end)
107 *val = strndup(start, end - start);
108 else
109 *val = strdup(start);
110 return 1;
111}
112
113
114static int get_command_arg_ull(const char *name,
115 unsigned long long *val)
116{
117 char *valstr;
118 char *end;
119
120 int ret = get_command_arg_str(name, &valstr);
121 if (ret <= 0)
122 return ret;
123
124 errno = 0;
125 *val = strtoll(valstr, &end, 10);
126 if (errno || *end) {
127 fprintf(stderr, "%s (%05d): ERROR: cannot parse %s value %s\n",
128 argv0, gettid(), name, valstr);
129 free(valstr);
130 return -1;
131 }
132 free(valstr);
133 return 0;
134}
135
136
137static int random_bytes(char *buf, size_t len)
138{
139 int fd;
140
141 fd = open("/dev/urandom", O_RDONLY);
142 if (fd < 0) {
143 fprintf(stderr, "%s (%05d): ERROR: cannot open /dev/urandom: %s\n",
144 argv0, gettid(), strerror(errno));
145 return -1;
146 }
147
148 if (read(fd, buf, len) != len) {
149 fprintf(stderr, "%s (%05d): ERROR: cannot read /dev/urandom: %s\n",
150 argv0, gettid(), strerror(errno));
151 close(fd);
152 return -1;
153 }
154
155 close(fd);
156
157 return 0;
158}
159
160
161static unsigned long long now(void)
162{
163 struct timeval tv;
164
165 gettimeofday(&tv, NULL);
166
167 return (tv.tv_sec * 1000ull) + (tv.tv_usec / 1000ull);
168}
169
170static int stressone(unsigned long long ramsizeMB)
171{
172 size_t pagesPerMB = 1024 * 1024 / PAGE_SIZE;
173 char *ram = malloc(ramsizeMB * 1024 * 1024);
174 char *ramptr;
175 size_t i, j, k;
176 char *data = malloc(PAGE_SIZE);
177 char *dataptr;
178 size_t nMB = 0;
179 unsigned long long before, after;
180
181 if (!ram) {
182 fprintf(stderr, "%s (%05d): ERROR: cannot allocate %llu MB of RAM: %s\n",
183 argv0, gettid(), ramsizeMB, strerror(errno));
184 return -1;
185 }
186 if (!data) {
187 fprintf(stderr, "%s (%d): ERROR: cannot allocate %d bytes of RAM: %s\n",
188 argv0, gettid(), PAGE_SIZE, strerror(errno));
189 free(ram);
190 return -1;
191 }
192
193
194
195
196
197
198 memset(ram, 0xfe, ramsizeMB * 1024 * 1024);
199
200 if (random_bytes(data, PAGE_SIZE) < 0) {
201 free(ram);
202 free(data);
203 return -1;
204 }
205
206 before = now();
207
208 while (1) {
209
210 ramptr = ram;
211 for (i = 0; i < ramsizeMB; i++, nMB++) {
212 for (j = 0; j < pagesPerMB; j++) {
213 dataptr = data;
214 for (k = 0; k < PAGE_SIZE; k += sizeof(long long)) {
215 ramptr += sizeof(long long);
216 dataptr += sizeof(long long);
217 *(unsigned long long *)ramptr ^= *(unsigned long long *)dataptr;
218 }
219 }
220
221 if (nMB == 1024) {
222 after = now();
223 fprintf(stderr, "%s (%05d): INFO: %06llums copied 1 GB in %05llums\n",
224 argv0, gettid(), after, after - before);
225 before = now();
226 nMB = 0;
227 }
228 }
229 }
230
231 free(data);
232 free(ram);
233}
234
235
236static void *stressthread(void *arg)
237{
238 unsigned long long ramsizeMB = *(unsigned long long *)arg;
239
240 stressone(ramsizeMB);
241
242 return NULL;
243}
244
245static int stress(unsigned long long ramsizeGB, int ncpus)
246{
247 size_t i;
248 unsigned long long ramsizeMB = ramsizeGB * 1024 / ncpus;
249 ncpus--;
250
251 for (i = 0; i < ncpus; i++) {
252 pthread_t thr;
253 pthread_create(&thr, NULL,
254 stressthread, &ramsizeMB);
255 }
256
257 stressone(ramsizeMB);
258
259 return 0;
260}
261
262
263static int mount_misc(const char *fstype, const char *dir)
264{
265 if (mkdir(dir, 0755) < 0 && errno != EEXIST) {
266 fprintf(stderr, "%s (%05d): ERROR: cannot create %s: %s\n",
267 argv0, gettid(), dir, strerror(errno));
268 return -1;
269 }
270
271 if (mount("none", dir, fstype, 0, NULL) < 0) {
272 fprintf(stderr, "%s (%05d): ERROR: cannot mount %s: %s\n",
273 argv0, gettid(), dir, strerror(errno));
274 return -1;
275 }
276
277 return 0;
278}
279
280static int mount_all(void)
281{
282 if (mount_misc("proc", "/proc") < 0 ||
283 mount_misc("sysfs", "/sys") < 0 ||
284 mount_misc("tmpfs", "/dev") < 0)
285 return -1;
286
287 mknod("/dev/urandom", 0777 | S_IFCHR, makedev(1, 9));
288 mknod("/dev/random", 0777 | S_IFCHR, makedev(1, 8));
289
290 return 0;
291}
292
293int main(int argc, char **argv)
294{
295 unsigned long long ramsizeGB = 1;
296 char *end;
297 int ch;
298 int opt_ind = 0;
299 const char *sopt = "hr:c:";
300 struct option lopt[] = {
301 { "help", no_argument, NULL, 'h' },
302 { "ramsize", required_argument, NULL, 'r' },
303 { "cpus", required_argument, NULL, 'c' },
304 { NULL, 0, NULL, 0 }
305 };
306 int ret;
307 int ncpus = 0;
308
309 argv0 = argv[0];
310
311 while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
312 switch (ch) {
313 case 'r':
314 errno = 0;
315 ramsizeGB = strtoll(optarg, &end, 10);
316 if (errno != 0 || *end) {
317 fprintf(stderr, "%s (%05d): ERROR: Cannot parse RAM size %s\n",
318 argv0, gettid(), optarg);
319 exit_failure();
320 }
321 break;
322
323 case 'c':
324 errno = 0;
325 ncpus = strtoll(optarg, &end, 10);
326 if (errno != 0 || *end) {
327 fprintf(stderr, "%s (%05d): ERROR: Cannot parse CPU count %s\n",
328 argv0, gettid(), optarg);
329 exit_failure();
330 }
331 break;
332
333 case '?':
334 case 'h':
335 fprintf(stderr, "%s: [--help][--ramsize GB][--cpus N]\n", argv0);
336 exit_failure();
337 }
338 }
339
340 if (getpid() == 1) {
341 if (mount_all() < 0)
342 exit_failure();
343
344 ret = get_command_arg_ull("ramsize", &ramsizeGB);
345 if (ret < 0)
346 exit_failure();
347 }
348
349 if (ncpus == 0)
350 ncpus = sysconf(_SC_NPROCESSORS_ONLN);
351
352 fprintf(stdout, "%s (%05d): INFO: RAM %llu GiB across %d CPUs\n",
353 argv0, gettid(), ramsizeGB, ncpus);
354
355 if (stress(ramsizeGB, ncpus) < 0)
356 exit_failure();
357
358 exit_success();
359}
360