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 { "B N","bigheap N", "start N workers that grow the heap using calloc()" },
29 { NULL, "bigheap-ops N", "stop after N bogo bigheap operations" },
30 { NULL, "bigheap-growth N", "grow heap by N bytes per iteration" },
31 { NULL, NULL, NULL }
32 };
33
34 /*
35 * stress_set_bigheap_growth()
36 * Set bigheap growth from given opt arg string
37 */
stress_set_bigheap_growth(const char * opt)38 static int stress_set_bigheap_growth(const char *opt)
39 {
40 uint64_t bigheap_growth;
41
42 bigheap_growth = stress_get_uint64_byte(opt);
43 stress_check_range_bytes("bigheap-growth", bigheap_growth,
44 MIN_BIGHEAP_GROWTH, MAX_BIGHEAP_GROWTH);
45 return stress_set_setting("bigheap-growth", TYPE_ID_UINT64, &bigheap_growth);
46 }
47
stress_bigheap_child(const stress_args_t * args,void * context)48 static int stress_bigheap_child(const stress_args_t *args, void *context)
49 {
50 uint64_t bigheap_growth = DEFAULT_BIGHEAP_GROWTH;
51 void *ptr = NULL, *last_ptr = NULL;
52 const size_t page_size = args->page_size;
53 const size_t stride = page_size;
54 size_t size = 0;
55 uint8_t *last_ptr_end = NULL;
56
57 (void)context;
58
59 if (!stress_get_setting("bigheap-growth", &bigheap_growth)) {
60 if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
61 bigheap_growth = MAX_BIGHEAP_GROWTH;
62 if (g_opt_flags & OPT_FLAGS_MINIMIZE)
63 bigheap_growth = MIN_BIGHEAP_GROWTH;
64 }
65 if (bigheap_growth < page_size)
66 bigheap_growth = page_size;
67
68 /* Round growth size to nearest page size */
69 bigheap_growth &= ~(page_size - 1);
70
71 stress_set_proc_state(args->name, STRESS_STATE_RUN);
72
73 do {
74 void *old_ptr = ptr;
75 size += (size_t)bigheap_growth;
76
77 /*
78 * With many instances running it is wise to
79 * double check before the next realloc as
80 * sometimes process start up is delayed for
81 * some time and we should bail out before
82 * exerting any more memory pressure
83 */
84 if (!keep_stressing(args))
85 goto abort;
86
87 ptr = realloc(old_ptr, size);
88 if (ptr == NULL) {
89 pr_dbg("%s: out of memory at %" PRIu64
90 " MB (instance %d)\n",
91 args->name, (uint64_t)(4096ULL * size) >> 20,
92 args->instance);
93 free(old_ptr);
94 size = 0;
95 } else {
96 size_t i, n;
97 uint8_t *u8ptr, *tmp;
98
99 if (last_ptr == ptr) {
100 tmp = u8ptr = last_ptr_end;
101 n = (size_t)bigheap_growth;
102 } else {
103 tmp = u8ptr = ptr;
104 n = size;
105 }
106 if (!keep_stressing(args))
107 goto abort;
108
109 if (page_size > 0) {
110 size_t sz = page_size - 1;
111 uintptr_t pg_ptr = ((uintptr_t)ptr + sz) & ~sz;
112 size_t len = size - (pg_ptr - (uintptr_t)ptr);
113
114 (void)stress_mincore_touch_pages_interruptible((void *)pg_ptr, len);
115 }
116
117 for (i = 0; i < n; i+= stride, u8ptr += stride) {
118 if (!keep_stressing(args))
119 goto abort;
120 *u8ptr = (uint8_t)i;
121 }
122
123 if (g_opt_flags & OPT_FLAGS_VERIFY) {
124 for (i = 0; i < n; i+= stride, tmp += stride) {
125 if (!keep_stressing(args))
126 goto abort;
127 if (*tmp != (uint8_t)i)
128 pr_fail("%s: byte at location %p was 0x%" PRIx8
129 " instead of 0x%" PRIx8 "\n",
130 args->name, (void *)u8ptr, *tmp, (uint8_t)i);
131 }
132 }
133 last_ptr = ptr;
134 last_ptr_end = u8ptr;
135 }
136 inc_counter(args);
137 } while (keep_stressing(args));
138 abort:
139 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
140
141 free(ptr);
142
143 return EXIT_SUCCESS;
144 }
145
146 /*
147 * stress_bigheap()
148 * stress heap allocation
149 */
stress_bigheap(const stress_args_t * args)150 static int stress_bigheap(const stress_args_t *args)
151 {
152 return stress_oomable_child(args, NULL, stress_bigheap_child, STRESS_OOMABLE_NORMAL);
153 }
154
155 static const stress_opt_set_func_t opt_set_funcs[] = {
156 { OPT_bigheap_growth, stress_set_bigheap_growth },
157 { 0, NULL },
158 };
159
160 stressor_info_t stress_bigheap_info = {
161 .stressor = stress_bigheap,
162 .class = CLASS_OS | CLASS_VM,
163 .opt_set_funcs = opt_set_funcs,
164 .help = help
165 };
166