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 #define DEFAULT_DELAY_NS (100000)
28 #define MAX_SAMPLES (10000)
29 #define MAX_BUCKETS (250)
30
31 typedef struct {
32 const int policy; /* scheduler policy */
33 const char *name; /* name of scheduler policy */
34 const char *opt_name; /* option name */
35 } stress_policy_t;
36
37 typedef struct {
38 int64_t min_ns; /* min latency */
39 int64_t max_ns; /* max latency */
40 int64_t latencies[MAX_SAMPLES];
41 size_t index; /* index into latencies */
42 int32_t min_prio; /* min priority allowed */
43 int32_t max_prio; /* max priority allowed */
44 double ns; /* total nanosecond latency */
45 double latency_mean; /* average latency */
46 int64_t latency_mode; /* first mode */
47 double std_dev; /* standard deviation */
48 } stress_rt_stats_t;
49
50 typedef int (*stress_cyclic_func)(const stress_args_t *args, stress_rt_stats_t *rt_stats, uint64_t cyclic_sleep);
51
52 typedef struct {
53 const char *name;
54 const stress_cyclic_func func;
55 } stress_cyclic_method_info_t;
56
57 static const stress_help_t help[] = {
58 { NULL, "cyclic N", "start N cyclic real time benchmark stressors" },
59 { NULL, "cyclic-ops N", "stop after N cyclic timing cycles" },
60 { NULL, "cyclic-method M", "specify cyclic method M, default is clock_ns" },
61 { NULL, "cyclic-dist N", "calculate distribution of interval N nanosecs" },
62 { NULL, "cyclic-policy P", "used rr or fifo scheduling policy" },
63 { NULL, "cyclic-prio N", "real time scheduling priority 1..100" },
64 { NULL, "cyclic-sleep N", "sleep time of real time timer in nanosecs" },
65 { NULL, NULL, NULL }
66 };
67
68 static const stress_policy_t policies[] = {
69 #if defined(SCHED_DEADLINE)
70 { SCHED_DEADLINE, "SCHED_DEADLINE", "deadline" },
71 #endif
72 #if defined(SCHED_FIFO)
73 { SCHED_FIFO, "SCHED_FIFO", "fifo" },
74 #endif
75 #if defined(SCHED_RR)
76 { SCHED_RR, "SCHED_RR", "rr" },
77 #endif
78 };
79
80 static const size_t num_policies = SIZEOF_ARRAY(policies);
81
stress_set_cyclic_sleep(const char * opt)82 static int stress_set_cyclic_sleep(const char *opt)
83 {
84 uint64_t cyclic_sleep;
85
86 cyclic_sleep = stress_get_uint64(opt);
87 stress_check_range("cyclic-sleep", cyclic_sleep,
88 1, STRESS_NANOSECOND);
89 return stress_set_setting("cyclic-sleep", TYPE_ID_UINT64, &cyclic_sleep);
90 }
91
stress_set_cyclic_policy(const char * opt)92 static int stress_set_cyclic_policy(const char *opt)
93 {
94 size_t policy;
95
96 for (policy = 0; policy < num_policies; policy++) {
97 if (!strcmp(opt, policies[policy].opt_name)) {
98 stress_set_setting("cyclic-policy", TYPE_ID_SIZE_T, &policy);
99 return 0;
100 }
101 }
102 (void)fprintf(stderr, "invalid cyclic-policy '%s', policies allowed are:", opt);
103 for (policy = 0; policy < num_policies; policy++) {
104 (void)fprintf(stderr, " %s", policies[policy].opt_name);
105 }
106 (void)fprintf(stderr, "\n");
107 return -1;
108 }
109
stress_set_cyclic_prio(const char * opt)110 static int stress_set_cyclic_prio(const char *opt)
111 {
112 int32_t cyclic_prio;
113
114 cyclic_prio = stress_get_int32(opt);
115 stress_check_range("cyclic-prio", (uint64_t)cyclic_prio, 1, 100);
116 return stress_set_setting("cyclic-prio", TYPE_ID_INT32, &cyclic_prio);
117 }
118
stress_set_cyclic_dist(const char * opt)119 static int stress_set_cyclic_dist(const char *opt)
120 {
121 uint64_t cyclic_dist;
122
123 cyclic_dist = stress_get_uint64(opt);
124 stress_check_range("cyclic-dist", cyclic_dist, 1, 10000000);
125 return stress_set_setting("cyclic-dist", TYPE_ID_UINT64, &cyclic_dist);
126 }
127
128 #if (defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_NANOSLEEP)) || \
129 (defined(HAVE_CLOCK_GETTIME) && defined(HAVE_NANOSLEEP)) || \
130 (defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PSELECT)) || \
131 (defined(HAVE_CLOCK_GETTIME))
stress_cyclic_stats(stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep,const struct timespec * t1,const struct timespec * t2)132 static void stress_cyclic_stats(
133 stress_rt_stats_t *rt_stats,
134 const uint64_t cyclic_sleep,
135 const struct timespec *t1,
136 const struct timespec *t2)
137 {
138 int64_t delta_ns;
139
140 delta_ns = ((int64_t)(t2->tv_sec - t1->tv_sec) * STRESS_NANOSECOND) +
141 (t2->tv_nsec - t1->tv_nsec);
142 delta_ns -= cyclic_sleep;
143
144 if (rt_stats->index < MAX_SAMPLES)
145 rt_stats->latencies[rt_stats->index++] = delta_ns;
146
147 rt_stats->ns += (double)delta_ns;
148 }
149 #endif
150
151 #if defined(HAVE_CLOCK_GETTIME) && \
152 defined(HAVE_CLOCK_NANOSLEEP)
153 /*
154 * stress_cyclic_clock_nanosleep()
155 * measure latencies with clock_nanosleep
156 */
stress_cyclic_clock_nanosleep(const stress_args_t * args,stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep)157 static int stress_cyclic_clock_nanosleep(
158 const stress_args_t *args,
159 stress_rt_stats_t *rt_stats,
160 const uint64_t cyclic_sleep)
161 {
162 struct timespec t1, t2, t, trem;
163 int ret;
164
165 (void)args;
166
167 t.tv_sec = cyclic_sleep / STRESS_NANOSECOND;
168 t.tv_nsec = cyclic_sleep % STRESS_NANOSECOND;
169 (void)clock_gettime(CLOCK_REALTIME, &t1);
170 ret = clock_nanosleep(CLOCK_REALTIME, 0, &t, &trem);
171 (void)clock_gettime(CLOCK_REALTIME, &t2);
172 if (ret == 0)
173 stress_cyclic_stats(rt_stats, cyclic_sleep, &t1, &t2);
174 return 0;
175 }
176 #endif
177
178 #if defined(HAVE_CLOCK_GETTIME) && \
179 defined(HAVE_NANOSLEEP)
180 /*
181 * stress_cyclic_posix_nanosleep()
182 * measure latencies with posix nanosleep
183 */
stress_cyclic_posix_nanosleep(const stress_args_t * args,stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep)184 static int stress_cyclic_posix_nanosleep(
185 const stress_args_t *args,
186 stress_rt_stats_t *rt_stats,
187 const uint64_t cyclic_sleep)
188 {
189 struct timespec t1, t2, t, trem;
190 int ret;
191
192 (void)args;
193
194 t.tv_sec = cyclic_sleep / STRESS_NANOSECOND;
195 t.tv_nsec = cyclic_sleep % STRESS_NANOSECOND;
196 (void)clock_gettime(CLOCK_REALTIME, &t1);
197 ret = nanosleep(&t, &trem);
198 (void)clock_gettime(CLOCK_REALTIME, &t2);
199 if (ret == 0)
200 stress_cyclic_stats(rt_stats, cyclic_sleep, &t1, &t2);
201 return 0;
202 }
203 #endif
204
205 #if defined(HAVE_CLOCK_GETTIME)
206 /*
207 * stress_cyclic_poll()
208 * measure latencies of heavy polling the clock
209 */
stress_cyclic_poll(const stress_args_t * args,stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep)210 static int stress_cyclic_poll(
211 const stress_args_t *args,
212 stress_rt_stats_t *rt_stats,
213 const uint64_t cyclic_sleep)
214 {
215 struct timespec t1, t2;
216
217 (void)args;
218
219 /* find nearest point to clock roll over */
220 (void)clock_gettime(CLOCK_REALTIME, &t1);
221 for (;;) {
222 (void)clock_gettime(CLOCK_REALTIME, &t2);
223 if ((t1.tv_sec != t2.tv_sec) || (t1.tv_nsec != t2.tv_nsec))
224 break;
225 }
226 t1 = t2;
227
228 for (;;) {
229 int64_t delta_ns;
230
231 (void)clock_gettime(CLOCK_REALTIME, &t2);
232
233 delta_ns = ((int64_t)(t2.tv_sec - t1.tv_sec) * STRESS_NANOSECOND) +
234 (t2.tv_nsec - t1.tv_nsec);
235 if (delta_ns >= (int64_t)cyclic_sleep) {
236 delta_ns -= cyclic_sleep;
237
238 if (rt_stats->index < MAX_SAMPLES)
239 rt_stats->latencies[rt_stats->index++] = delta_ns;
240
241 rt_stats->ns += (double)delta_ns;
242 break;
243 }
244 }
245 return 0;
246 }
247 #endif
248
249 #if defined(HAVE_PSELECT) && \
250 defined(HAVE_CLOCK_GETTIME)
251 /*
252 * stress_cyclic_pselect()
253 * measure latencies with pselect sleep
254 */
stress_cyclic_pselect(const stress_args_t * args,stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep)255 static int stress_cyclic_pselect(
256 const stress_args_t *args,
257 stress_rt_stats_t *rt_stats,
258 const uint64_t cyclic_sleep)
259 {
260 struct timespec t1, t2, t;
261 int ret;
262
263 (void)args;
264
265 t.tv_sec = cyclic_sleep / STRESS_NANOSECOND;
266 t.tv_nsec = cyclic_sleep % STRESS_NANOSECOND;
267 (void)clock_gettime(CLOCK_REALTIME, &t1);
268 ret = pselect(0, NULL, NULL,NULL, &t, NULL);
269 (void)clock_gettime(CLOCK_REALTIME, &t2);
270 if (ret == 0)
271 stress_cyclic_stats(rt_stats, cyclic_sleep, &t1, &t2);
272 return 0;
273 }
274 #endif
275
276 #if defined(HAVE_CLOCK_GETTIME) && \
277 defined(HAVE_TIMER_CREATE) && \
278 defined(HAVE_TIMER_DELETE) && \
279 defined(HAVE_TIMER_SETTIME)
280 static struct timespec itimer_time;
281
stress_cyclic_itimer_handler(int sig)282 static void MLOCKED_TEXT stress_cyclic_itimer_handler(int sig)
283 {
284 (void)sig;
285
286 (void)clock_gettime(CLOCK_REALTIME, &itimer_time);
287 }
288
289 /*
290 * stress_cyclic_itimer()
291 * measure latencies with itimers
292 */
stress_cyclic_itimer(const stress_args_t * args,stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep)293 static int stress_cyclic_itimer(
294 const stress_args_t *args,
295 stress_rt_stats_t *rt_stats,
296 const uint64_t cyclic_sleep)
297 {
298 struct itimerspec timer;
299 struct timespec t1;
300 int64_t delta_ns;
301 struct sigaction old_action;
302 struct sigevent sev;
303 timer_t timerid;
304 int ret = -1;
305
306 timer.it_interval.tv_sec = timer.it_value.tv_sec = cyclic_sleep / STRESS_NANOSECOND;
307 timer.it_interval.tv_nsec = timer.it_value.tv_nsec = cyclic_sleep % STRESS_NANOSECOND;
308
309 if (stress_sighandler(args->name, SIGRTMIN, stress_cyclic_itimer_handler, &old_action) < 0)
310 return ret;
311
312 (void)memset(&sev, 0, sizeof(sev));
313 sev.sigev_notify = SIGEV_SIGNAL;
314 sev.sigev_signo = SIGRTMIN;
315 sev.sigev_value.sival_ptr = &timerid;
316 if (timer_create(CLOCK_REALTIME, &sev, &timerid) < 0)
317 goto restore;
318
319 (void)memset(&itimer_time, 0, sizeof(itimer_time));
320 (void)clock_gettime(CLOCK_REALTIME, &t1);
321 if (timer_settime(timerid, 0, &timer, NULL) < 0)
322 goto restore;
323
324 (void)pause();
325 if ((itimer_time.tv_sec == 0) &&
326 (itimer_time.tv_nsec == 0))
327 goto tidy;
328
329 delta_ns = ((int64_t)(itimer_time.tv_sec - t1.tv_sec) * STRESS_NANOSECOND) +
330 (itimer_time.tv_nsec - t1.tv_nsec);
331 delta_ns -= cyclic_sleep;
332
333 if (rt_stats->index < MAX_SAMPLES)
334 rt_stats->latencies[rt_stats->index++] = delta_ns;
335
336 rt_stats->ns += (double)delta_ns;
337
338 (void)timer_delete(timerid);
339
340 ret = 0;
341 tidy:
342 /* And cancel timer */
343 (void)memset(&timer, 0, sizeof(timer));
344 (void)timer_settime(timerid, 0, &timer, NULL);
345 restore:
346 stress_sigrestore(args->name, SIGRTMIN, &old_action);
347 return ret;
348 }
349 #endif
350
351 #if defined(HAVE_CLOCK_GETTIME)
352 /*
353 * stress_cyclic_usleep()
354 * measure latencies with usleep
355 */
stress_cyclic_usleep(const stress_args_t * args,stress_rt_stats_t * rt_stats,const uint64_t cyclic_sleep)356 static int stress_cyclic_usleep(
357 const stress_args_t *args,
358 stress_rt_stats_t *rt_stats,
359 const uint64_t cyclic_sleep)
360 {
361 struct timespec t1, t2;
362 const useconds_t usecs = (useconds_t)cyclic_sleep / 1000;
363 int ret;
364
365 (void)args;
366
367 (void)clock_gettime(CLOCK_REALTIME, &t1);
368 ret = usleep(usecs);
369 (void)clock_gettime(CLOCK_REALTIME, &t2);
370 if (ret == 0)
371 stress_cyclic_stats(rt_stats, cyclic_sleep, &t1, &t2);
372 return 0;
373 }
374 #endif
375
376 static sigjmp_buf jmp_env;
377
378 /*
379 * stress_rlimit_handler()
380 * rlimit generic handler
381 */
stress_rlimit_handler(int signum)382 static void NORETURN MLOCKED_TEXT stress_rlimit_handler(int signum)
383 {
384 (void)signum;
385
386 keep_stressing_set_flag(false);
387 siglongjmp(jmp_env, 1);
388 }
389
390 /*
391 * stress_cyclic_cmp()
392 * sort latencies into order, least first
393 */
stress_cyclic_cmp(const void * p1,const void * p2)394 static int stress_cyclic_cmp(const void *p1, const void *p2)
395 {
396 const int64_t *i1 = (const int64_t *)p1;
397 const int64_t *i2 = (const int64_t *)p2;
398
399 if (*i1 > *i2)
400 return 1;
401 else if (*i1 < *i2)
402 return -1;
403 return 0;
404 }
405
406 /*
407 * stress_rt_stats()
408 * compute statistics on gathered latencies
409 */
stress_rt_stats(stress_rt_stats_t * rt_stats)410 static void stress_rt_stats(stress_rt_stats_t *rt_stats)
411 {
412 size_t i;
413 size_t n = 0, best_n = 0;
414 int64_t current;
415 double variance = 0.0;
416
417 rt_stats->latency_mean = 0.0;
418 rt_stats->latency_mode = 0;
419
420 for (i = 0; i < rt_stats->index; i++) {
421 int64_t ns = rt_stats->latencies[i];
422
423 if (ns > rt_stats->max_ns)
424 rt_stats->max_ns = ns;
425 if (ns < rt_stats->min_ns)
426 rt_stats->min_ns = ns;
427
428 rt_stats->latency_mean += (double)ns;
429 }
430 if (rt_stats->index)
431 rt_stats->latency_mean /= (double)rt_stats->index;
432
433 qsort(rt_stats->latencies, rt_stats->index, sizeof(*(rt_stats->latencies)), stress_cyclic_cmp);
434
435 current = rt_stats->latency_mode = rt_stats->latencies[0];
436
437 for (i = 0; i < rt_stats->index; i++) {
438 int64_t ns = rt_stats->latencies[i];
439 double diff;
440
441 if (ns == current) {
442 n++;
443 if (n > best_n) {
444 rt_stats->latency_mode = current;
445 best_n = n;
446 }
447 } else {
448 current = ns;
449 n = 0;
450 }
451 diff = ((double)ns - rt_stats->latency_mean);
452 variance += (diff * diff);
453 }
454 if (rt_stats->index) {
455 variance /= (double)rt_stats->index;
456 rt_stats->std_dev = sqrt(variance);
457 }
458 }
459
460 /*
461 * cyclic methods
462 */
463 static const stress_cyclic_method_info_t cyclic_methods[] = {
464 #if defined(HAVE_CLOCK_GETTIME) && \
465 defined(HAVE_CLOCK_NANOSLEEP)
466 { "clock_ns", stress_cyclic_clock_nanosleep },
467 #endif
468
469 #if defined(HAVE_CLOCK_GETTIME) && \
470 defined(HAVE_TIMER_CREATE) && \
471 defined(HAVE_TIMER_DELETE) && \
472 defined(HAVE_TIMER_SETTIME)
473 { "itimer", stress_cyclic_itimer },
474 #endif
475
476 #if defined(HAVE_CLOCK_GETTIME)
477 { "poll", stress_cyclic_poll },
478 #endif
479
480 #if defined(HAVE_CLOCK_GETTIME) && \
481 defined(HAVE_NANOSLEEP)
482 { "posix_ns", stress_cyclic_posix_nanosleep },
483 #endif
484
485 #if defined(HAVE_PSELECT) && \
486 defined(HAVE_CLOCK_GETTIME)
487 { "pselect", stress_cyclic_pselect },
488 #endif
489
490 #if defined(HAVE_CLOCK_GETTIME)
491 { "usleep", stress_cyclic_usleep },
492 #endif
493
494 { NULL, NULL }
495 };
496
497 /*
498 * stress_set_cyclic_method()
499 * set the default cyclic method
500 */
stress_set_cyclic_method(const char * name)501 static int stress_set_cyclic_method(const char *name)
502 {
503 stress_cyclic_method_info_t const *info;
504
505 for (info = cyclic_methods; info->func; info++) {
506 if (!strcmp(info->name, name)) {
507 stress_set_setting("cyclic-method", TYPE_ID_UINTPTR_T, &info);
508 return 0;
509 }
510 }
511
512 (void)fprintf(stderr, "cyclic-method must be one of:");
513 for (info = cyclic_methods; info->func; info++) {
514 (void)fprintf(stderr, " %s", info->name);
515 }
516 (void)fprintf(stderr, "\n");
517
518 return -1;
519 }
520
521 /*
522 * stress_rt_dist()
523 * show real time distribution
524 */
stress_rt_dist(const char * name,bool * lock,stress_rt_stats_t * rt_stats,const int64_t cyclic_dist)525 static void stress_rt_dist(
526 const char *name,
527 bool *lock,
528 stress_rt_stats_t *rt_stats,
529 const int64_t cyclic_dist)
530 {
531 ssize_t dist_max_size = (cyclic_dist > 0) ?
532 ((ssize_t)rt_stats->max_ns / (ssize_t)cyclic_dist) + 1 : 1;
533 ssize_t dist_size = STRESS_MINIMUM(MAX_BUCKETS, dist_max_size);
534 const ssize_t dist_min = STRESS_MINIMUM(5, dist_max_size);
535 ssize_t i, n;
536 int64_t dist[dist_size];
537
538 if (!cyclic_dist)
539 return;
540
541 (void)memset(dist, 0, sizeof(dist));
542
543 for (i = 0; i < (ssize_t)rt_stats->index; i++) {
544 int64_t lat = rt_stats->latencies[i] / cyclic_dist;
545
546 if (lat < (int64_t)dist_size)
547 dist[lat]++;
548 }
549
550 for (n = dist_size; n >= 1; n--) {
551 if (dist[n - 1])
552 break;
553 }
554 if (n < dist_min)
555 n = dist_min;
556 if (n >= dist_size - 3)
557 n = dist_size;
558
559 pr_inf_lock(lock, "%s: latency distribution (%" PRIu64 " ns intervals):\n", name, cyclic_dist);
560 pr_inf_lock(lock, "%s: (for the first %zd buckets of %zd)\n", name, dist_size, dist_max_size);
561 pr_inf_lock(lock, "%s: %12s %10s\n", name, "latency (ns)", "frequency");
562 for (i = 0; i < n; i++) {
563 pr_inf_lock(lock, "%s: %12" PRIu64 " %10" PRId64 "\n",
564 name, cyclic_dist * i, dist[i]);
565 }
566
567 /*
568 * This caters for the case where there are lots of zeros at
569 * the end of the distribution
570 */
571 if (n < dist_size) {
572 pr_inf_lock(lock, "%s: %12s %10s (all zeros hereafter)\n", name, "..", "..");
573 pr_inf_lock(lock, "%s: %12s %10s\n", name, "..", "..");
574 for (i = STRESS_MAXIMUM(dist_size - 3, n); i < dist_size; i++) {
575 pr_inf_lock(lock, "%s: %12" PRIu64 " %10" PRId64 "\n",
576 name, cyclic_dist * i, (int64_t)0);
577 }
578 }
579 }
580
581 /*
582 * stress_cyclic_supported()
583 * check if we can run this as root
584 */
stress_cyclic_supported(const char * name)585 static int stress_cyclic_supported(const char *name)
586 {
587 if (!stress_check_capability(SHIM_CAP_SYS_NICE)) {
588 pr_inf_skip("%s stressor needs to be run with CAP_SYS_NICE "
589 "set SCHED_RR, SCHED_FIFO or SCHED_DEADLINE priorities, "
590 "skipping this stressor\n", name);
591 return -1;
592 }
593 return 0;
594 }
595
stress_cyclic(const stress_args_t * args)596 static int stress_cyclic(const stress_args_t *args)
597 {
598 const stress_cyclic_method_info_t *cyclic_method = &cyclic_methods[0];
599 const uint32_t num_instances = args->num_instances;
600 struct sigaction old_action_xcpu;
601 struct rlimit rlim;
602 pid_t pid;
603 NOCLOBBER uint64_t timeout;
604 uint64_t cyclic_sleep = DEFAULT_DELAY_NS;
605 uint64_t cyclic_dist = 0;
606 int32_t cyclic_prio = INT32_MAX;
607 int policy;
608 size_t cyclic_policy = 0;
609 const double start = stress_time_now();
610 stress_rt_stats_t *rt_stats;
611 const size_t page_size = args->page_size;
612 const size_t size = (sizeof(*rt_stats) + page_size - 1) & (~(page_size - 1));
613 stress_cyclic_func func;
614
615 timeout = g_opt_timeout;
616 (void)stress_get_setting("cyclic-sleep", &cyclic_sleep);
617 (void)stress_get_setting("cyclic-prio", &cyclic_prio);
618 (void)stress_get_setting("cyclic-policy", &cyclic_policy);
619 (void)stress_get_setting("cyclic-dist", &cyclic_dist);
620 (void)stress_get_setting("cyclic-method", &cyclic_method);
621
622 func = cyclic_method->func;
623 policy = policies[cyclic_policy].policy;
624
625 if (!args->instance) {
626 if (num_policies == 0) {
627 pr_inf_skip("%s: no scheduling policies "
628 "available, skipping test\n",
629 args->name);
630 return EXIT_NOT_IMPLEMENTED;
631 }
632 }
633
634 if (g_opt_timeout == TIMEOUT_NOT_SET) {
635 timeout = 60;
636 pr_inf("%s: timeout has not been set, forcing timeout to "
637 "be %" PRIu64 " seconds\n", args->name, timeout);
638 }
639
640 if ((num_instances > 1) && (args->instance == 0)) {
641 pr_inf("%s: for best results, run just 1 instance of "
642 "this stressor\n", args->name);
643 }
644
645 rt_stats = (stress_rt_stats_t *)mmap(NULL, size, PROT_READ | PROT_WRITE,
646 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
647 if (rt_stats == MAP_FAILED) {
648 pr_inf("%s: mmap of shared policy data failed: %d (%s)\n",
649 args->name, errno, strerror(errno));
650 return EXIT_NO_RESOURCE;
651 }
652 rt_stats->min_ns = INT64_MAX;
653 rt_stats->max_ns = INT64_MIN;
654 rt_stats->ns = 0.0;
655 #if defined(HAVE_SCHED_GET_PRIORITY_MIN)
656 rt_stats->min_prio = sched_get_priority_min(policy);
657 #else
658 rt_stats->min_prio = 0;
659 #endif
660
661 #if defined(HAVE_SCHED_GET_PRIORITY_MAX)
662 rt_stats->max_prio = sched_get_priority_max(policy);
663 #else
664 rt_stats->max_prio = 0;
665 #endif
666 /* If user has set max priority.. */
667 if (cyclic_prio != INT32_MAX) {
668 if (rt_stats->max_prio > cyclic_prio) {
669 rt_stats->max_prio = cyclic_prio;
670 }
671 }
672
673 if (args->instance == 0)
674 pr_dbg("%s: using method '%s'\n", args->name, cyclic_method->name);
675
676 stress_set_proc_state(args->name, STRESS_STATE_RUN);
677
678 again:
679 pid = fork();
680 if (pid < 0) {
681 if (stress_redo_fork(errno))
682 goto again;
683 if (!keep_stressing(args))
684 goto finish;
685 pr_inf("%s: cannot fork, errno=%d (%s)\n",
686 args->name, errno, strerror(errno));
687 return EXIT_NO_RESOURCE;
688 } else if (pid == 0) {
689 #if defined(HAVE_SCHED_GET_PRIORITY_MIN) && \
690 defined(HAVE_SCHED_GET_PRIORITY_MAX)
691 const pid_t mypid = getpid();
692 #endif
693 #if defined(HAVE_ATOMIC)
694 uint32_t count;
695 #endif
696 int ret;
697 NOCLOBBER int rc = EXIT_FAILURE;
698
699 #if defined(HAVE_ATOMIC)
700 __sync_fetch_and_add(&g_shared->softlockup_count, 1);
701
702 /*
703 * Wait until all instances have reached this point
704 */
705 do {
706 if ((stress_time_now() - start) > (double)timeout)
707 goto tidy_ok;
708 (void)usleep(50000);
709 __atomic_load(&g_shared->softlockup_count, &count, __ATOMIC_RELAXED);
710 } while (keep_stressing(args) && count < num_instances);
711 #endif
712
713 /*
714 * We run the stressor as a child so that
715 * if we the hard time timits the child is
716 * terminated with a SIGKILL and we can
717 * catch that with the parent
718 */
719 rlim.rlim_cur = timeout;
720 rlim.rlim_max = timeout;
721 (void)setrlimit(RLIMIT_CPU, &rlim);
722
723 #if defined(RLIMIT_RTTIME)
724 rlim.rlim_cur = 1000000 * timeout;
725 rlim.rlim_max = 1000000 * timeout;
726 (void)setrlimit(RLIMIT_RTTIME, &rlim);
727 #endif
728
729 if (stress_sighandler(args->name, SIGXCPU, stress_rlimit_handler, &old_action_xcpu) < 0)
730 goto tidy;
731
732 ret = sigsetjmp(jmp_env, 1);
733 if (ret)
734 goto tidy_ok;
735
736 #if defined(HAVE_SCHED_GET_PRIORITY_MIN) && \
737 defined(HAVE_SCHED_GET_PRIORITY_MAX)
738 #if defined(SCHED_DEADLINE)
739 redo_policy:
740 #endif
741 ret = stress_set_sched(mypid, policy, rt_stats->max_prio, true);
742 if (ret < 0) {
743 #if defined(SCHED_DEADLINE)
744 /*
745 * The following occurs if we use an older kernel
746 * that does not support the larger newer attr structure
747 * but userspace does. This currently only occurs with
748 * SCHED_DEADLINE; fall back to the next scheduling policy
749 * which users the older and smaller attr structure.
750 */
751 if ((errno == E2BIG) &&
752 (policies[cyclic_policy].policy == SCHED_DEADLINE)) {
753 cyclic_policy = 1;
754 policy = policies[cyclic_policy].policy;
755 #if defined(HAVE_SCHED_GET_PRIORITY_MAX)
756 rt_stats->max_prio = sched_get_priority_max(policy);
757 #else
758 rt_stats->max_prio = 0;
759 #endif
760 pr_inf("%s: DEADLINE not supported by kernel, defaulting to %s\n",
761 args->name, policies[cyclic_policy].name);
762 goto redo_policy;
763 }
764 #endif
765 if (errno != EPERM) {
766 const char *msg = (errno == EBUSY) ?
767 ", (recommend setting --sched-runtime to less than 90000)" : "";
768
769 pr_fail("%s: sched_setscheduler "
770 "failed: errno=%d (%s) "
771 "for scheduler policy %s%s\n",
772 args->name, errno, strerror(errno),
773 policies[cyclic_policy].name,
774 msg);
775 }
776 goto tidy;
777 }
778 #endif
779 do {
780 func(args, rt_stats, cyclic_sleep);
781 inc_counter(args);
782
783 /* Ensure we NEVER spin forever */
784 if ((stress_time_now() - start) > (double)timeout)
785 break;
786 } while (keep_stressing(args));
787
788 tidy_ok:
789 rc = EXIT_SUCCESS;
790 tidy:
791 (void)fflush(stdout);
792 _exit(rc);
793 } else {
794 int status, ret;
795
796 ret = stress_set_sched(args->pid, policy, rt_stats->max_prio, true);
797 (void)ret;
798
799 (void)pause();
800 (void)kill(pid, SIGKILL);
801 #if defined(HAVE_ATOMIC)
802 __sync_fetch_and_sub(&g_shared->softlockup_count, 1);
803 #endif
804
805 (void)shim_waitpid(pid, &status, 0);
806 }
807
808 stress_rt_stats(rt_stats);
809
810 if (args->instance == 0) {
811 if (rt_stats->index) {
812 size_t i;
813 bool lock = false;
814
815 static const double percentiles[] = {
816 25.0,
817 50.0,
818 75.0,
819 90.0,
820 95.40,
821 99.0,
822 99.5,
823 99.9,
824 99.99,
825 };
826
827 pr_lock(&lock);
828 pr_inf_lock(&lock, "%s: sched %s: %" PRIu64 " ns delay, %zd samples\n",
829 args->name,
830 policies[cyclic_policy].name,
831 cyclic_sleep,
832 rt_stats->index);
833 pr_inf_lock(&lock, "%s: mean: %.2f ns, mode: %" PRId64 " ns\n",
834 args->name,
835 rt_stats->latency_mean,
836 rt_stats->latency_mode);
837 pr_inf_lock(&lock, "%s: min: %" PRId64 " ns, max: %" PRId64 " ns, std.dev. %.2f\n",
838 args->name,
839 rt_stats->min_ns,
840 rt_stats->max_ns,
841 rt_stats->std_dev);
842
843 pr_inf_lock(&lock, "%s: latency percentiles:\n", args->name);
844 for (i = 0; i < sizeof(percentiles) / sizeof(percentiles[0]); i++) {
845 size_t j = (size_t)(((double)rt_stats->index * percentiles[i]) / 100.0);
846 pr_inf_lock(&lock, "%s: %5.2f%%: %10" PRId64 " ns\n",
847 args->name,
848 percentiles[i],
849 rt_stats->latencies[j]);
850 }
851 stress_rt_dist(args->name, &lock, rt_stats, (int64_t)cyclic_dist);
852 pr_unlock(&lock);
853 } else {
854 pr_inf("%s: %10s: no latency information available\n",
855 args->name,
856 policies[cyclic_policy].name);
857 }
858 }
859
860 finish:
861 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
862
863 (void)munmap((void *)rt_stats, size);
864
865 return EXIT_SUCCESS;
866 }
867
868 static const stress_opt_set_func_t opt_set_funcs[] = {
869 { OPT_cyclic_dist, stress_set_cyclic_dist },
870 { OPT_cyclic_method, stress_set_cyclic_method },
871 { OPT_cyclic_policy, stress_set_cyclic_policy },
872 { OPT_cyclic_prio, stress_set_cyclic_prio },
873 { OPT_cyclic_sleep, stress_set_cyclic_sleep },
874 { 0, NULL }
875 };
876
877 stressor_info_t stress_cyclic_info = {
878 .stressor = stress_cyclic,
879 .supported = stress_cyclic_supported,
880 .class = CLASS_SCHEDULER | CLASS_OS,
881 .opt_set_funcs = opt_set_funcs,
882 .help = help
883 };
884