1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2002
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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
13 * the 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 /* 11/19/2002 Port to LTP robbiew@us.ibm.com */
21 /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
22
23 /*
24 * NAME
25 * stack_space.c - stack test
26 *
27 * Test VM for set of stack-space intensive programs.
28 * This code very similar to tdat.c, only uses stack-based "file".
29 *
30 */
31
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <sys/wait.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <string.h>
40
41 /** LTP Port **/
42 #include "test.h"
43
44 #define FAILED 0
45 #define PASSED 1
46
47 int local_flag = PASSED;
48 int block_number;
49
50 char *TCID = "stack_space"; /* Test program identifier. */
51 int TST_TOTAL = 1; /* Total number of test cases. */
52 /**************/
53
54 #define MAXCHILD 100 /* max # kids */
55 #define K_1 1024
56 #define K_2 2048
57 #define K_4 4096
58 #define MAXSIZE 10*K_1
59
60 int nchild; /* # kids */
61 int csize; /* chunk size */
62 int iterations; /* # total iterations */
63 int parent_pid;
64
65 int usage(char *);
66 int bd_arg(char *);
67 int runtest();
68 int dotest(int, int);
69 int bfill(char *, char, int);
70 int dumpbuf(char *);
71 void dumpbits(char *, int);
72
73 char *prog; /* invoked name */
74
usage(char * prog)75 int usage(char *prog)
76 {
77 tst_resm(TCONF, "Usage: %s <nchild> <chunk_size> <iterations>", prog);
78 tst_brkm(TCONF, NULL, "DEFAULTS: 20 1024 50");
79 }
80
main(argc,argv)81 int main(argc, argv)
82 int argc;
83 char *argv[];
84 {
85 register int i;
86 void term();
87
88 prog = argv[0];
89 parent_pid = getpid();
90
91 if (signal(SIGTERM, term) == SIG_ERR) {
92 tst_brkm(TBROK, NULL, "first sigset failed");
93
94 }
95
96 if (argc == 1) {
97 nchild = 20;
98 csize = K_1;
99 iterations = 50;
100 } else if (argc == 4) {
101 i = 1;
102 if (sscanf(argv[i++], "%d", &nchild) != 1)
103 bd_arg(argv[i - 1]);
104 if (nchild > MAXCHILD) {
105 tst_brkm(TBROK, NULL,
106 "Too many children, max is %d",
107 MAXCHILD);
108 }
109 if (sscanf(argv[i++], "%d", &csize) != 1)
110 bd_arg(argv[i - 1]);
111 if (csize > MAXSIZE) {
112 tst_brkm(TBROK, NULL,
113 "Chunk size too large , max is %d",
114 MAXSIZE);
115 }
116 if (sscanf(argv[i++], "%d", &iterations) != 1)
117 bd_arg(argv[i - 1]);
118 } else
119 usage(prog);
120
121 tst_tmpdir();
122 runtest();
123 /**NOT REACHED**/
124 return 0;
125
126 }
127
bd_arg(str)128 int bd_arg(str)
129 char *str;
130 {
131 tst_brkm(TCONF, NULL,
132 "Bad argument - %s - could not parse as number.",
133 str);
134 }
135
runtest()136 int runtest()
137 {
138 register int i;
139 int child;
140 int status;
141 int count;
142
143 for (i = 0; i < nchild; i++) {
144 if ((child = fork()) == 0) { /* child */
145 dotest(nchild, i); /* do it! */
146 exit(0); /* when done, exit */
147 }
148 if (child < 0) {
149 tst_resm(TBROK,
150 "Fork failed (may be OK if under stress)");
151 tst_resm(TINFO, "System resource may be too low.");
152 tst_brkm(TBROK, tst_rmdir, "Reason: %s",
153 strerror(errno));
154
155 }
156 }
157
158 /*
159 * Wait for children to finish.
160 */
161
162 count = 0;
163 while ((child = wait(&status)) > 0) {
164 #ifdef DEBUG
165 tst_resm(TINFO, "\t%s[%d] exited status = 0x%x\n", prog, child,
166 status);
167 #endif
168 if (status) {
169 tst_resm(TINFO, "\tFailed - expected 0 exit status.");
170 local_flag = FAILED;
171 }
172 ++count;
173 }
174
175 /*
176 * Should have collected all children.
177 */
178
179 if (count != nchild) {
180 tst_resm(TINFO, "\tWrong # children waited on, count = %d",
181 count);
182 local_flag = FAILED;
183 }
184
185 (local_flag == FAILED) ? tst_resm(TFAIL, "Test failed")
186 : tst_resm(TPASS, "Test passed");
187 sync(); /* safeness */
188 tst_rmdir();
189 tst_exit();
190
191 }
192
193 /*
194 * dotest()
195 * Children execute this.
196 *
197 * Randomly read/mod/write chunks with known pattern and check.
198 * When fill sectors, iterate.
199 */
200
201 int nchunks;
202
203 #define CHUNK(i) ((i) * csize)
204
dotest(int testers,int me)205 int dotest(int testers, int me)
206 {
207 char *bits;
208 char *val_buf;
209 char *zero_buf;
210 char *buf;
211 int count;
212 int collide;
213 char val;
214 int chunk;
215 char mondobuf[MAXSIZE];
216
217 nchunks = MAXSIZE / csize;
218 bits = malloc((nchunks + 7) / 8);
219 val_buf = (char *)(malloc(csize));
220 zero_buf = (char *)(malloc(csize));
221
222 if (bits == 0 || val_buf == 0 || zero_buf == 0) {
223 tst_brkm(TFAIL, NULL, "\tmalloc failed, pid: %d", getpid());
224 }
225
226 /*
227 * No init sectors; allow file to be sparse.
228 */
229
230 val = (64 / testers) * me + 1;
231
232 /*
233 * For each iteration:
234 * zap bits array
235 * loop:
236 * pick random chunk.
237 * if corresponding bit off {
238 * verify == 0. (sparse file)
239 * ++count;
240 * } else
241 * verify == val.
242 * write "val" on it.
243 * repeat until count = nchunks.
244 * ++val.
245 * Fill-in those chunks not yet seen.
246 */
247
248 bfill(zero_buf, 0, csize);
249 bfill(mondobuf, 0, MAXSIZE);
250
251 srand(getpid());
252 while (iterations-- > 0) {
253 bfill(bits, 0, (nchunks + 7) / 8);
254 bfill(val_buf, val, csize);
255 count = 0;
256 collide = 0;
257 while (count < nchunks) {
258 chunk = rand() % nchunks;
259 buf = mondobuf + CHUNK(chunk);
260
261 /*
262 * If bit off, haven't seen it yet.
263 * Else, have. Verify values.
264 */
265
266 if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0) {
267 if (memcmp(buf, zero_buf, csize)) {
268 tst_resm(TFAIL,
269 "%s[%d] bad verify @ %d (%p) for val %d count %d, should be 0.",
270 prog, me, chunk, buf, val,
271 count);
272 tst_resm(TINFO, "Prev ");
273 dumpbuf(buf - csize);
274 dumpbuf(buf);
275 tst_resm(TINFO, "Next ");
276 dumpbuf(buf + csize);
277 dumpbits(bits, (nchunks + 7) / 8);
278 tst_exit();
279 }
280 bits[chunk / 8] |= (1 << (chunk % 8));
281 ++count;
282 } else {
283 ++collide;
284 if (memcmp(buf, val_buf, csize)) {
285 tst_resm(TFAIL,
286 "%s[%d] bad verify @ %d (%p) for val %d count %d.",
287 prog, me, chunk, buf, val,
288 count);
289 tst_resm(TINFO, "Prev ");
290 dumpbuf(buf - csize);
291 dumpbuf(buf);
292 tst_resm(TINFO, "Next ");
293 dumpbuf(buf + csize);
294 dumpbits(bits, (nchunks + 7) / 8);
295 tst_exit();
296 }
297 }
298
299 /*
300 * Write it.
301 */
302
303 bfill(buf, val, csize);
304
305 if (count + collide > 2 * nchunks)
306 break;
307 }
308
309 /*
310 * End of iteration, maybe before doing all chunks.
311 */
312
313 for (chunk = 0; chunk < nchunks; chunk++) {
314 if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0)
315 bfill(mondobuf + CHUNK(chunk), val, csize);
316 }
317 bfill(zero_buf, val, csize);
318 ++val;
319 }
320 free(bits);
321 free(val_buf);
322 free(zero_buf);
323
324 return 0;
325 }
326
bfill(buf,val,size)327 int bfill(buf, val, size)
328 register char *buf;
329 char val;
330 register int size;
331 {
332 register int i;
333
334 for (i = 0; i < size; i++)
335 buf[i] = val;
336 return 0;
337 }
338
339 /*
340 * dumpbuf
341 * Dump the buffer.
342 */
343
dumpbuf(buf)344 int dumpbuf(buf)
345 register char *buf;
346 {
347 register int i;
348 char val;
349 int idx;
350 int nout;
351
352 #ifdef DEBUG
353 tst_resm(TINFO, "Buf: ... ");
354 for (i = -10; i < 0; i++)
355 tst_resm(TINFO, "%x, ", buf[i]);
356 tst_resm(TINFO, "\n");
357 #endif
358
359 nout = 0;
360 idx = 0;
361 val = buf[0];
362 for (i = 0; i < csize; i++) {
363 if (buf[i] != val) {
364 #ifdef DEBUG
365 if (i == idx + 1)
366 tst_resm(TINFO, "%x, ", buf[idx] & 0xff);
367 else
368 tst_resm(TINFO, "%d*%x, ", i - idx,
369 buf[idx] & 0xff);
370 #endif
371 idx = i;
372 val = buf[i];
373 ++nout;
374 }
375 if (nout > 10) {
376 #ifdef DEBUG
377 tst_resm(TINFO, " ... more\n");
378 #endif
379 return 0;
380 }
381 }
382 #ifdef DEBUG
383 if (i == idx + 1)
384 tst_resm(TINFO, "%x\n", buf[idx] & 0xff);
385 else
386 tst_resm(TINFO, "%d*%x\n", i - idx, buf[idx]);
387 #endif
388 return 0;
389
390 }
391
392 /*
393 * dumpbits
394 * Dump the bit-map.
395 */
396
dumpbits(bits,size)397 void dumpbits(bits, size)
398 char *bits;
399 register int size;
400 {
401 #ifdef DEBUG
402 register char *buf;
403
404 tst_resm(TINFO, "Bits array:");
405 for (buf = bits; size > 0; --size, ++buf) {
406 if ((buf - bits) % 16 == 0)
407 tst_resm(TINFO, "\n%04x:\t", 8 * (buf - bits));
408 tst_resm(TINFO, "%02x ", (int)*buf & 0xff);
409 }
410 tst_resm(TINFO, "\n");
411 #endif
412
413 }
414
term()415 void term()
416 {
417
418 if (getpid() == parent_pid) {
419 #ifdef DEBUG
420 tst_resm(TINFO, "term - parent - got SIGTERM.\n");
421 #endif
422 } else {
423 #ifdef DEBUG
424 tst_resm(TINFO, "term1 - child - exiting\n");
425 #endif
426 exit(0);
427 }
428 }
429